#include "dryctrlthread.h"
#include "rtdb.h"
#include  <math.h>

#define SIGNAL_LOG_COUNT 60

//#define EMS_CTRL_SWITCH_CLOSE_STR    "IO控制汇流开关合闸."
//#define EMS_CTRL_SWITCH_OPEN_STR     "IO控制汇流开关分闸."
//#define SERIAL_IO_DEV_CONN_ERROR	"串口继电器通信故障."
//#define SERIAL_IO_DEV_CONN_OK		"串口继电器通信恢复."

//#define SWITCH_CLOSED_STR    		"汇流开关合闸."
//#define SWITCH_OPENED_STR     	"汇流开关分闸."

//unsigned char  g_DIState = 0;// 4路继电器输出4路开关量输入（转发卡） 的DI状态 DI1和DI2闭合时值为3， 只有DI3闭合时值为4
//unsigned char  g_DOState = 0;// 4路继电器输出4路开关量输入（转发卡） 的DO状态 DO1和DO2闭合时值为3， 只有DO3闭合时值为4
//int      g_bReadDiFlag = 0; // 是否已经获取到DI状态
//int      g_bReadDoFlag = 0; // 是否已经获取到DO状态
//quint16  g_connFailedCount = 0; // 通迅故障计时，通迅正常时清0

int g_testCount = 0;

// added 2024-10-28
QString getDOName(QList<int> list)
{
    QString strName;
    for(int i = 0; i < list.size(); ++i)
    {
        int doIndex = list.at(i);
        if(i > 0)
            strName += ",";
        strName += QString("DO%1").arg(doIndex);
    }

    return strName;
}

void limitAlmCount(quint16 &devAlarmCount)
{
    if (devAlarmCount > 10000)  //防止次数太大溢出
    {
        devAlarmCount = 10000;
    }
}

/*
3.8.0、2.0.0项目通用
aEnvTemp[30]水浸告警使能aEnvTemp[31]水浸告警
aEnvTemp[32]消防告警使能aEnvTemp[33]消防告警
aEnvTemp[34]消防启动使能aEnvTemp[35]消防启动
aEnvTemp[36]消防故障使能aEnvTemp[37]消防故障
*/
char old485Alarm[10] = {0,0,0,0,0,0,0,0,0,0};
char g_runCount = 1;
int g_masterHZCmd = 0; // added 204-4-26
char has485WaterAlarm(int type) // added 2024-1-6
{
    char ret = 0;
    if(0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS
    if(1 == type)
    {
        ret = 1;
    }
    else
    {
        if(1)
        {
            char tmpVal = 0;//KgGlobalData::ms_pStack->aEnvTemp[31];
            if((KgGlobalData::ms_pStack->aEnvWaterAlarm[0]&2) > 0)
                tmpVal = 1;
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[0] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生水浸告警(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Has water alarm(protocal comm)."));
                }
                if(old485Alarm[0] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("水浸告警结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Water alarm is over(protocal comm)."));
                }
            }
            old485Alarm[0] = tmpVal;
        }
    }

#else
    if(1 == type)
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[30])
            ret = 1;
    }
    else
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[30])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[31];
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[0] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生水浸告警(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Has water alarm(protocal comm)."));

                }
                if(old485Alarm[0] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("水浸告警结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Water alarm is over(protocal comm)."));
                }
            }
            old485Alarm[0] = tmpVal;
        }
    }
#endif
    return ret;
}

char has485XfWarm(int type) // added 2024-1-6
{
    char ret = 0;
    if(0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS // added 2024-10-27
    if(1 == type)
    {
        ret = 1;
    }
    else
    {
        if(1)
        {
            CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
            char tmpVal = 0;// KgGlobalData::ms_pStack->aEnvTemp[33];
            if(1 == pXfData->usDevTemp[1])
                tmpVal = 1;
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[1] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生消防告警(协议通迅)."));// 485
                    else
                        saveLogToBaDb(kgConvert("Has fire alarm(protocal comm)."));

                }
                if(old485Alarm[1] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防告警结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Fire alarm is over(protocal comm)."));

                }
            }
            old485Alarm[1] = tmpVal;
        }
    }
#else
    if(1 == type)
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[32])
            ret = 1;
    }
    else
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[32])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[33];
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[1] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生消防告警(协议通迅)."));// 485
                    else
                        saveLogToBaDb(kgConvert("Has fire alarm(protocal comm)."));
                }
                if(old485Alarm[1] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防告警结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Fire alarm is over(protocal comm)."));
                }
            }
            old485Alarm[1] = tmpVal;
        }
    }

#endif
    return ret;
}

char has485XfMotion(int type)
{
    char ret = 0;
    if(0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS // added 2024-10-27
    if(1 == type)
    {
        ret = 1;
    }
    else
    {
        if(1)
        {
            CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
            char tmpVal = 0;//KgGlobalData::ms_pStack->aEnvTemp[35];
            if(1 == pXfData->usDevTemp[0] || pXfData->usDevTemp[1] > 1)
                tmpVal = 1;
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[2] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生消防启动(协议通迅)."));// 485
                    else
                        saveLogToBaDb(kgConvert("Has fire action(protocal comm)."));
                }
                if(old485Alarm[2] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防启动结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Fire action is over(protocal comm)."));
                }
            }
            old485Alarm[2] = tmpVal;
        }
    }
#else
    if(1 == type)
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[34])
            ret = 1;
    }
    else
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[34])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[35];
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[2] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生消防启动(协议通迅)."));// 485
                    else
                        saveLogToBaDb(kgConvert("Has fire action(protocal comm)."));
                }
                if(old485Alarm[2] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防启动结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Fire action is over(protocal comm)."));
                }
            }
            old485Alarm[2] = tmpVal;
        }
    }
#endif
    return ret;
}

char has485XfFault(int type)
{
    char ret = 0;
    if(0 == KgGlobalData::ms_enabled485Alarm)
        return 0;
#ifdef VER20_EMS // added 2024-10-27
    if(1 == type)
    {
        ret = 1;
    }
    else
    {
        if(1)
        {
            CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
            char tmpVal = 0;//KgGlobalData::ms_pStack->aEnvTemp[37];
            if(2 == pXfData->usDevTemp[0])
                tmpVal = 1;
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[3] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生消防故障(协议通迅)."));// 485
                    else
                        saveLogToBaDb(kgConvert("Has fire fault(protocal comm)."));
                }
                if(old485Alarm[3] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防故障结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Fire fault is over(protocal comm)."));
                }
            }
            old485Alarm[3] = tmpVal;
        }
    }

#else
    if(1 == type)
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[36])
            ret = 1;
    }
    else
    {
        if(1 == KgGlobalData::ms_pStack->aEnvTemp[36])
        {
            char tmpVal = KgGlobalData::ms_pStack->aEnvTemp[37];
            ret = tmpVal;
            if(g_runCount > 0)
            {
                if(0 == old485Alarm[3] && tmpVal > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("发生消防故障(协议通迅)."));// 485
                    else
                        saveLogToBaDb(kgConvert("Has fire fault(protocal comm)."));
                }
                if(old485Alarm[3] > 0 && 0 == tmpVal)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防故障结束(协议通迅)."));
                    else
                        saveLogToBaDb(kgConvert("Fire fault is over(protocal comm)."));
                }
            }
            old485Alarm[3] = tmpVal;
        }
    }
#endif
    return ret;
}

void DryCtrlThread::sendLog(int iLogType, const QString& strLog)
{
    writeKgLogfile(strLog);
}

DryCtrlThread::DryCtrlThread(QObject *parent)
    : QThread(parent)
{
    m_pIOReader = new IOReader(this, KgGlobalData::ms_comDevName);
    m_pStack = 0;
    m_fireAlarmCount = 0;
    m_fireAlarm = 0;
    m_fireAlarm = 0;
    // m_fireDetectAlarm = 0;
    m_oldFireAlarm = 0;
    m_fireSignal = 0;

    m_fireSprayCount = 0;
    m_fireSpraySignal = 0;
    m_fireSprayAlarm = 0;
    m_oldFireSprayAlarm = 0;

    m_fireFaultCount = 0;
    m_fireFaultAlarm = 0;

    m_waterCount = 0;
    m_waterAlarm = 0;
    m_waterSignal = 0;

    m_thunderCount = 0;
    m_thunderAlarm = 0;
    m_thunderSignal = 0;

    m_emergStopCount = 0;
    m_emergStopAlarm = 0;
    m_usOldEmerStopState = 0;
    m_emergStopSignal = 0;

    m_waterCountSec = 0;
    m_waterAlarmSec = 0;
    m_waterSignalSec = 0;

    m_thunderCountSec = 0;
    m_thunderAlarmSec = 0;
    m_thunderSignalSec = 0;

    m_emergStopCountSec = 0;
    m_emergStopAlarmSec = 0;
    m_emergStopSignalSec = 0;

    m_bmsLocalCount = 0;
    m_bmsLocalSignal = 0;
    m_bmsLocalState = 0;  // 1:BMS就地 0:BMS远方

    m_bmsRemoteCount = 0;
    m_bmsRemoteSignal = 0;
    m_bmsRemoteState = 0;  // 1:BMS远方 0:S就地

    m_combusGasCount = 0;
    m_combusGasAlarm = 0;
    m_combusGasDetectAlarm = 0;
    m_combusGasSignal = 0;

    m_fuseCount = 0;
    m_fuseAlarm = 0;
    m_fuseSignal = 0;

    m_xfMotionCount = 0;
    m_xfMotionAlarm = 0;

    m_fireManuCount = 0;
    m_fireManuMode = 0;

    m_elecPowerOffCount = 0;
    m_elecPowerOffAlarm = 0;

    m_xfWarmCount= 0;
    m_xfWarmMsg= 0;

    m_upsAlarmCount = 0;
    m_upsAlarm= 0;

    m_doorAlarmCount = 0;
    m_doorAlarm= 0;

    m_doorAlarmCountSec = 0;
    m_doorAlarmSec = 0;

    m_acFaultCount = 0;
    m_acFault = 0;

    m_lqFaultCount = 0;
    m_lqFault = 0;

    m_bmsSmokeCount = 0;
    m_bmsSmokeAlarm = 0;
    m_bmsSmokeMotionLogCount = 0;

    m_bmsHeatCount = 0;
    m_bmsHeatAlarm = 0;
    m_bmsHeatMotionLogCount = 0;

    m_stackState = 0;                // 当前堆状态
    m_statChangeTime = QDateTime();  // 堆状态改变时间

    //m_hlkgState = 99;
    for(int i = 0; i < MAX_HLKG_COUNT; ++i)
    {
        m_hlkgState[i] = 99;
    }

    for(int i = 0; i < MAX_GLKG_COUNT; ++i)
    {
        m_glkgState[i] = 99;
    }

    for(int i = 0; i < 10; ++i)
    {
        m_bankFaultTimeCount[i] = 0;
    }


    m_drvFzCount = 0;   // 已发送分闸/脱扣命令记数
    m_drvFzSuccedCount = 0;
    //drvFzTime;      // 最近一次驱动分闸时间

    m_drvHzCount = 0;   // 已发送合闸命令记数
    m_drvHzSuccedCount = 0;

    m_oldConnState = 0; // 并网连接状态

    m_masterFzCount = 0;// 主动分闸记数
    m_masterHzCount = 0;// 主动合闸记数

    m_saveEmsCtrlHzRdCount = 0;// 保存EMS控制汇流开关记录后计时
    m_saveEmsCtrlFzRdCount = 0;
    m_saveRejectEmsHzRdCount = 0;

    m_detectYcCount = 0;
    m_detectOkCount = 0;

    //m_setDoCount = 0;

    m_usOldHasAlarm = 0;
    m_usOldHasProt = 0;

    m_usConnFailed = 99; // 是否有通迅故障 0:无 1:有, 99:没有初始化

    m_usOldChgJcqState = 99;
    m_usOldDchgJcqState = 99;

    //m_iLogCount = 0;

    m_xfTkMotionCount = 0;
    m_xfTkMotionLogCount = 0;
    m_emgTkMotionLogCount = 0;

    m_waterTkMotionLogCount = 0;
    m_xfSprayTkMotionCount = 0;
    m_xfSprayTkMotionLogCount = 0;

    m_volDownProtTkCount = 0;
    m_volDownProtTkLogCount = 0;

    m_signalLogCount = 0;

    m_isolSwitchClosedCount = 0;
    m_isolSwitchOpendCount = 0;

    m_xfAlarmLog = 0;
    m_xfXfMotionLog = 0;
    m_xfXfErrorLog = 0;

    m_hasReadIoState = 0;
    for(int i = 0; i < 16; ++i)
    {
        m_usOldDI[i] = 0;
    }

    for(int i = 0; i < MAX_BANK_NUM; ++i)
    {
        m_oldBankState[i] = 0;
    }

    for(int i = 0; i < RES_STRATEGY_COUNT; ++i)
    {
        m_reservedAlarm[i] = 0;
        m_reservedCount[i] = 0;
    }
    

    for(int i = 0; i < EXT_STRATEGY_COUNT; ++i)
    {
        m_extAlarm[i] = 0;
        m_extCount[i] = 0;
    }

    m_oldCtrlFanState = 0;
    m_closeFanReqCount = 0;

    m_mainSwitchCount = 0;
    m_mainSwitchClosed = 0;

    this->netDebug = new QNetDebug();
    netDebug->init("192.168.1.74", 7777);  // Server IP and port
    netDebug->setApplicationName("MyApplication");
    m_doCloseCounter =0;

    CBattBank *pFirstBank = KgGlobalData::ms_pRTDB->getBank(0);

    pFirstBank->usBankHoldTemp[49] = 0;

    bool m_addressAllocCommandSent = false;
}

DryCtrlThread::~DryCtrlThread()
{

}

// 判断对应的干结点是否发生告警 added 2021-2-22
// bool HasAlarmVal(XFStrategy stg, unsigned char dIState, int type, QString &strPos) // modifed 2023-3-13
bool HasAlarmVal(XFStrategy stg, int dIState, int type, QString &strPos)
{
    bool bAlarm = false;
    for(int i = 0; i < stg.diList.size(); ++i)
    {
        DI_STU diStu = stg.diList[i];
        int xfMask = 1 << diStu.diIndex;
        //printf("dIState==========%d\n", dIState);
        if (1 == diStu.alarmValue) // 常开干结点
        {
            if (xfMask == (xfMask & dIState))// 有告警
            {
                bAlarm = true;
                if (strPos.length() > 0)
                {
                    strPos +=",";
                }
                strPos += QString("%1").arg(0+diStu.diIndex);
            }
            else
            {
                ;
            }
        }
        else  // 常闭干结点
        {
            if (xfMask == (xfMask & dIState))
            {

            }
            else // 有告警
            {
                bAlarm = true;
                if (strPos.length() > 0)
                {
                    strPos +=",";
                }
                strPos += QString("%1").arg(0+diStu.diIndex);
            }
        }
    }

    return bAlarm;
}

void DryCtrlThread::judgeXfAlarm()
{
    // sendLog(0, "==============judgeXfAlarm() step1");
    if (KgGlobalData::ms_xfStrategy.diList.size() > 0 || has485XfWarm(1)) // 有采集消防信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireAlarmCount >= KgGlobalData::ms_xfStrategy.confirmedCount)
            {
                if (0 == m_fireAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_xfStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_fireAlarm  = 1;
                //sendLog(0, "==============judgeXfAlarm()  step2");
                sendLog(0, QString("******************fireAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireAlarmCount);
        }
        else
        {
            //sendLog(0, "==============judgeXfAlarm()  step3");
            if (1 == m_fireAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_xfStrategy.diOverName);
            }

            m_fireAlarmCount = 0;
            m_fireAlarm = 0;
            //m_fireDetectAlarm = 0;
            m_fireSignal = 0;
            //sendLog(0, "fireAlarm is 0");
        }

        //KgGlobalData::ms_pStack->aEnvFireAction = m_fireAlarm;
        //KgGlobalData::ms_pStack->aFireWarn = m_fireAlarm; // 消防告警 modified 2023-3-13
        char xfAlarm485 = has485XfWarm(2);
#ifdef VER20_EMS // added 2024-4-28
        /*CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
        if(pXfData)
        {
            if(xfAlarm485 > 0) // 消防报警
                pXfData->fireAlarm = xfAlarm485;
            else if(1 == m_fireAlarm)
                pXfData->fireAlarm = 1;
            else
                pXfData->fireAlarm = 0;
        }*/
#endif
        if(xfAlarm485 > 0 || 1 == m_fireAlarm)
        {
            KgGlobalData::ms_pStack->aFireWarn = 1;
        }
        else
        {
            KgGlobalData::ms_pStack->aFireWarn = 0;
        }
    }
    // sendLog(0, "==============judgeXfAlarm()  step4");
}

void DryCtrlThread::judgeXfSparyAlam() // added 2022-12-10
{
    if (KgGlobalData::ms_xfSprayStrategy.diList.size() > 0 || has485XfMotion(1)) // 有采集消防喷洒信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfSprayStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireSprayCount >= KgGlobalData::ms_xfSprayStrategy.confirmedCount)
            {
                if (0 == m_fireSprayAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_xfSprayStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_fireSprayAlarm  = 1;
                sendLog(0, QString("******************fireSprayAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireSprayCount);
        }
        else
        {
            if (1 == m_fireSprayAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_xfSprayStrategy.diOverName);
            }

            m_fireSprayCount = 0;
            m_fireSprayAlarm = 0;
            m_fireSpraySignal = 0;
        }

        //KgGlobalData::ms_pStack->aFireAction = m_fireSprayAlarm; // modified 2023-3-13
        char xfSpray485 = has485XfMotion(2);
#ifdef VER20_EMS // added 2024-4-28
        /*CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
        if(pXfData)
        {
            if(xfSpray485 > 0) // 消防启动
                pXfData->spryAlarm = xfSpray485;
            else if(1 == m_fireSprayAlarm)
                pXfData->spryAlarm = 1;
            else
                pXfData->spryAlarm = 0;
        }*/
#endif
        if(xfSpray485 > 0 || 1 == m_fireSprayAlarm)
        {
            KgGlobalData::ms_pStack->aFireAction = 1;
        }
        else
        {
            KgGlobalData::ms_pStack->aFireAction = 0;
        }
    }
}

void DryCtrlThread::judgeXfFaultAlam() // added 2022-12-21
{
    if (KgGlobalData::ms_xfFaultStrategy.diList.size() > 0 || has485XfFault(1)) // 有采集消防故障信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfFaultStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireFaultCount >= KgGlobalData::ms_xfFaultStrategy.confirmedCount)
            {
                if (0 == m_fireFaultAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_xfFaultStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_fireFaultAlarm  = 1;
                sendLog(0, QString("******************fireFaultAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireFaultCount);
        }
        else
        {
            if (1 == m_fireFaultAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_xfFaultStrategy.diOverName);
            }

            m_fireFaultCount = 0;
            m_fireFaultAlarm = 0;
        }

        //KgGlobalData::ms_pStack->aEnvFireFault = m_fireFaultAlarm;
        //KgGlobalData::ms_pStack->aFireFault = m_fireFaultAlarm;        // 消防故障
        char xfFault485 = has485XfFault(2);
#ifdef VER20_EMS // added 2024-4-28
        /*CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
        if(pXfData)
        {
            if(xfFault485 > 0) // 消防设备故障
                pXfData->devError = xfFault485;
            else if(1 == m_fireFaultAlarm)
                pXfData->devError = 1;
            else
                pXfData->devError = 0;
        }*/
#endif
        if(xfFault485 > 0 || 1 == m_fireFaultAlarm)
        {
            KgGlobalData::ms_pStack->aFireFault = 1;
        }
        else
        {
            KgGlobalData::ms_pStack->aFireFault = 0;
        }
    }
}

void DryCtrlThread::judgeXfAutoManu()  //  27
{
    if (KgGlobalData::ms_xfManuAutoStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfManuAutoStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_fireManuCount >= KgGlobalData::ms_xfManuAutoStrategy.confirmedCount)
            {
                if (0 == m_fireManuMode)
                {
                    saveLogToBaDb(KgGlobalData::ms_xfManuAutoStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_fireManuMode  = 1;
                sendLog(0, QString("******************Xf ManuMode(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fireManuCount);
        }
        else
        {
            if (1 == m_fireManuMode)
            {
                saveLogToBaDb(KgGlobalData::ms_xfManuAutoStrategy.diOverName);
            }

            m_fireManuCount = 0;
            m_fireManuMode = 0;
        }

        KgGlobalData::ms_pStack->aEnvTemp[15] = m_fireManuMode;
    }
}

void DryCtrlThread::judgeElecPowerOff()  //  27
{
    if (KgGlobalData::ms_elecPowerOffStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_elecPowerOffStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_elecPowerOffCount >= KgGlobalData::ms_elecPowerOffStrategy.confirmedCount)
            {
                if (0 == m_elecPowerOffAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_elecPowerOffStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_elecPowerOffAlarm  = 1;
                sendLog(0, QString("******************Elec power off(DI%1)").arg(strPos));
            }

            limitAlmCount(m_elecPowerOffCount);
        }
        else
        {
            if (1 == m_elecPowerOffAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_elecPowerOffStrategy.diOverName);
            }

            m_elecPowerOffCount = 0;
            m_elecPowerOffAlarm = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[18] = m_elecPowerOffAlarm;
    }
}

void DryCtrlThread::judgeWaterAlarm()
{
    if (KgGlobalData::ms_waterStrategy.diList.size() > 0) // 有采集水浸信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_waterStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_waterCount >= KgGlobalData::ms_waterStrategy.confirmedCount)
            {
                if (0 == m_waterAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_waterStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_waterAlarm  = 1;
                sendLog(0, QString("******************waterAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_waterCount);
        }
        else
        {
            if (1 == m_waterAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_waterStrategy.diOverName);
            }
            m_waterCount = 0;
            m_waterAlarm = 0;
            m_waterSignal = 0;
        }
        KgGlobalData::ms_pStack->aEnvWaterAlarm[0] = m_waterAlarm;
        //KgGlobalData::ms_pStack->aWaterAlarm = m_waterAlarm;                       // 水浸告警
    }
}

void DryCtrlThread::judgeWaterAlarmSec()
{
    if (KgGlobalData::ms_waterStrategySec.diList.empty())
        return;

    QString strPos;
    if (HasAlarmVal(KgGlobalData::ms_waterStrategySec, KgGlobalData::ms_dryData.DIVal, 1, strPos))
    {
        if (++m_waterCountSec >= KgGlobalData::ms_waterStrategySec.confirmedCount)
        {
            if (!m_waterAlarmSec)
                saveLogToBaDb(KgGlobalData::ms_waterStrategySec.diName + QString("(DI%1).").arg(strPos));

            m_waterAlarmSec = 1;
            sendLog(0, QString("******************2# WaterAlarm(DI%1)").arg(strPos));
        }
        limitAlmCount(m_waterCountSec);
    }
    else
    {
        if (m_waterAlarmSec)
            saveLogToBaDb(KgGlobalData::ms_waterStrategySec.diOverName);

        m_waterCountSec = 0;
        m_waterAlarmSec = 0;
        m_waterSignalSec = 0;
    }

    KgGlobalData::ms_pStack->aEnvWaterAlarm[1] = m_waterAlarmSec;
}

void DryCtrlThread::judgeThunderAlarm()
{
    if (KgGlobalData::ms_tdStrategy.diList.size() > 0)  // 有采集防雷信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_tdStrategy, KgGlobalData::ms_dryData.DIVal,2,strPos))
        {
            if(++m_thunderCount >= KgGlobalData::ms_tdStrategy.confirmedCount)
            {
                if (0 == m_thunderAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_tdStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_thunderAlarm  = 1;
                sendLog(0, QString("******************ThunderAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_thunderCount);
        }
        else
        {
            if (1 == m_thunderAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_tdStrategy.diOverName);
            }
            m_thunderCount = 0;
            m_thunderAlarm = 0;
            m_thunderSignal = 0;
            //sendLog(0, "thunderAlarm is 0");
        }
        //KgGlobalData::ms_pStack->aStackTemp[5] = m_thunderAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[12] = m_thunderAlarm;
    }
}

void DryCtrlThread::judgeThunderAlarmSec()
{
    if (KgGlobalData::ms_tdStrategySec.diList.size() > 0)  // 有采集防雷信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_tdStrategySec, KgGlobalData::ms_dryData.DIVal,2,strPos))
        {
            if(++m_thunderCountSec >= KgGlobalData::ms_tdStrategySec.confirmedCount)
            {
                if (0 == m_thunderAlarmSec)
                {
                    saveLogToBaDb(KgGlobalData::ms_tdStrategySec.diName + QString("(DI%1).").arg(strPos));
                }
                m_thunderAlarmSec  = 1;
                sendLog(0, QString("******************2# ThunderAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_thunderCountSec);
        }
        else
        {
            if (1 == m_thunderAlarmSec)
            {
                saveLogToBaDb(KgGlobalData::ms_tdStrategySec.diOverName);
            }
            m_thunderCountSec = 0;
            m_thunderAlarmSec = 0;
            m_thunderSignalSec = 0;
            //sendLog(0, "thunderAlarm is 0");
        }
        //KgGlobalData::ms_pStack->aStackTemp[5] = m_thunderAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[13] = m_thunderAlarmSec;
    }
}

void DryCtrlThread::judgeEmergeStop()
{
    if (KgGlobalData::ms_emgStopStrategy.diList.size() > 0) // 有采集急停信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_emgStopStrategy, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if(++m_emergStopCount  >= KgGlobalData::ms_emgStopStrategy.confirmedCount)
            {
                if (0 == m_emergStopAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_emgStopStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_emergStopAlarm  = 1;
                sendLog(0, QString("******************EmergStopAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_emergStopCount);
        }
        else
        {
            if (1 == m_emergStopAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_emgStopStrategy.diOverName);
            }
            m_emergStopCount = 0;
            m_emergStopAlarm = 0;
            m_emergStopSignal = 0;
            //sendLog(0, "emergStopAlarm is 0");
        }

        if (m_emergStopAlarm) // 发生急停
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 1;
            ///KgGlobalData::ms_pStack->aEmerStop = 1;
            //writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        else       // 正常
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 2;
            ///KgGlobalData::ms_pStack->aEmerStop = 0;
            //writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        //KgGlobalData::ms_pStack->aEmerStop = m_emergStopAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[21] = m_emergStopAlarm;
    }
}

void DryCtrlThread::judgeEmergeStopSec()
{
    if (KgGlobalData::ms_emgStopStrategySec.diList.size() > 0) // 有采集急停信号
    {

        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_emgStopStrategySec, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if(++m_emergStopCountSec  >= KgGlobalData::ms_emgStopStrategySec.confirmedCount)
            {
                if (0 == m_emergStopAlarmSec)
                {
                    saveLogToBaDb(KgGlobalData::ms_emgStopStrategySec.diName + QString("(DI%1).").arg(strPos));
                }
                m_emergStopAlarmSec  = 1;
                sendLog(0, QString("******************2# EmergStopAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_emergStopCountSec);
        }
        else
        {
            if (1 == m_emergStopAlarmSec)
            {
                saveLogToBaDb(KgGlobalData::ms_emgStopStrategySec.diOverName);
            }
            m_emergStopCountSec = 0;
            m_emergStopAlarmSec = 0;
            m_emergStopSignalSec = 0;
            //sendLog(0, "emergStopAlarm is 0");
        }

        if (m_emergStopAlarmSec) // 发生急停
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 1;
            //KgGlobalData::ms_pStack->aEmerStop = 1;
            //writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        else       // 正常
        {
            //KgGlobalData::ms_pStack->usEmerStopState = 2;
            //KgGlobalData::ms_pStack->aEmerStop = 0;
            //writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
        }
        // KgGlobalData::ms_pStack->aEmerStop = m_emergStopAlarm;
        KgGlobalData::ms_pStack->aEnvTemp[11] = m_emergStopAlarmSec;
    }
}

void DryCtrlThread::judgeBmsLocalState()// added 2023-12-25
{
    if (KgGlobalData::ms_bmsLocalStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_bmsLocalStrategy, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if(++m_bmsLocalCount >= KgGlobalData::ms_bmsLocalStrategy.confirmedCount)
            {
                if (0 == m_bmsLocalState)
                {
                    saveLogToBaDb(KgGlobalData::ms_bmsLocalStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_bmsLocalState  = 1;
                sendLog(0, QString("******************Bms is local state(DI%1)").arg(strPos));
            }

            limitAlmCount(m_bmsLocalCount);
        }
        else
        {
            if (1 == m_bmsLocalState)
            {
                saveLogToBaDb(KgGlobalData::ms_bmsLocalStrategy.diOverName);
            }
            m_bmsLocalCount = 0;
            m_bmsLocalState = 0;
            m_bmsLocalSignal = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[19] = m_bmsLocalState;
    }
}

void DryCtrlThread::judgeBmsRemoteState()
{
    if (KgGlobalData::ms_bmsRemmoteStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_bmsRemmoteStrategy, KgGlobalData::ms_dryData.DIVal,3,strPos))
        {
            if(++m_bmsRemoteCount >= KgGlobalData::ms_bmsRemmoteStrategy.confirmedCount)
            {
                if (0 == m_bmsRemoteState)
                {
                    saveLogToBaDb(KgGlobalData::ms_bmsRemmoteStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_bmsRemoteState  = 1;
                sendLog(0, QString("******************Bms is remote state(DI%1)").arg(strPos));
            }

            limitAlmCount(m_bmsRemoteCount);
        }
        else
        {
            if (1 == m_bmsRemoteState)
            {
                saveLogToBaDb(KgGlobalData::ms_bmsRemmoteStrategy.diOverName);
            }
            m_bmsRemoteCount = 0;
            m_bmsRemoteState = 0;
            m_bmsRemoteSignal = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[20] = m_bmsRemoteState;
    }
}

// added 2022-3-27
void DryCtrlThread::judgeFuseAlarm()
{
    if (KgGlobalData::ms_fuseStrategy.diList.size() > 0)  // 有采集熔断器信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_fuseStrategy, KgGlobalData::ms_dryData.DIVal,4,strPos))
        {
            if(++m_fuseCount >= KgGlobalData::ms_fuseStrategy.confirmedCount)
            {
                if (0 == m_fuseAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_fuseStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_fuseAlarm  = 1;
                sendLog(0, QString("******************FuseAlarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_fuseCount);
        }
        else
        {
            if (1 == m_fuseAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_fuseStrategy.diOverName);
            }
            m_fuseCount = 0;
            m_fuseAlarm = 0;
            m_fuseSignal = 0;
            //sendLog(0, "fuseAlarm is 0");
        }
        KgGlobalData::ms_pStack->aEnvTemp[17] = m_fuseAlarm;
    }
}

// 读取消防释放告警 // added 2022-4-6
void DryCtrlThread::judgeXfMotionMsg()
{
    if (KgGlobalData::ms_xfMotionStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfMotionStrategy, KgGlobalData::ms_dryData.DIVal, 5, strPos))
        {
            if(++m_xfMotionCount >= KgGlobalData::ms_xfMotionStrategy.confirmedCount)
            {
                if (0 == m_xfMotionAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_xfMotionStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_xfMotionAlarm = 1;
                sendLog(0, QString("******************Fire motion Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_xfMotionCount);
        }
        else
        {
            if (1 == m_xfMotionAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_xfMotionStrategy.diOverName);
            }
            m_xfMotionCount = 0;
            m_xfMotionAlarm = 0;
        }

        KgGlobalData::ms_pStack->aFireAction = m_xfMotionAlarm; // modified 2023-3-13

#ifdef ND_VER_PROGRAM 	// 南都版本 
        if (m_xfMotionAlarm) // 消防释放
        {
            KgGlobalData::ms_pStack->usStackTotAlarm = KgGlobalData::ms_pStack->usStackTotAlarm | (1 << 7);
        }
        else  // 正常
        {
            KgGlobalData::ms_pStack->usStackTotAlarm = KgGlobalData::ms_pStack->usStackTotAlarm & (~(1 << 7));
        }
        //printf("===============================usStackTotAlarm %d\n", KgGlobalData::ms_pStack->usStackTotAlarm);
#endif
    }
}

// 读取消防预警信号 // added 2022-6-8
void DryCtrlThread::judgeXfWarmMsg()
{
    bool bHasWarm = 0;
    if (KgGlobalData::ms_xfWarmStrategy.diList.size() > 0)
    {
        bHasWarm = 1;
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_xfWarmStrategy, KgGlobalData::ms_dryData.DIVal, 6, strPos))
        {
            if(++m_xfWarmCount >= KgGlobalData::ms_xfWarmStrategy.confirmedCount)
            {
                if (0 == m_xfWarmMsg)
                {
                    saveLogToBaDb(KgGlobalData::ms_xfWarmStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_xfWarmMsg = 1;
                sendLog(0, QString("******************Fire warm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_xfWarmCount);
        }
        else
        {
            if (1 == m_xfWarmMsg)
            {
                saveLogToBaDb(KgGlobalData::ms_xfWarmStrategy.diOverName);
            }
            m_xfWarmCount = 0;
            m_xfWarmMsg = 0;
        }

        //KgGlobalData::ms_pStack->aEnvFireWarn = m_xfWarmMsg;
        if(KgGlobalData::ms_bXfWarnTellBmsed > 0)
        {
            KgGlobalData::ms_pStack->aFireWarn = m_xfWarmMsg; // 消防预警
        }
        KgGlobalData::ms_pStack->aEnvTemp[14] = m_xfWarmMsg;
    }
}

void DryCtrlThread::judgeUpsAlarm()
{
    if (KgGlobalData::ms_upsAlmStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_upsAlmStrategy, KgGlobalData::ms_dryData.DIVal, 7, strPos))
        {
            if(++m_upsAlarmCount >= KgGlobalData::ms_upsAlmStrategy.confirmedCount)
            {
                if (0 == m_upsAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_upsAlmStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_upsAlarm = 1;
                sendLog(0, QString("******************UPS Fault(DI%1)").arg(strPos));
            }

            limitAlmCount(m_upsAlarmCount);
        }
        else
        {
            if (1 == m_upsAlarm)//if (1 == m_xfWarmMsg)// 2024-4-24
            {
                saveLogToBaDb(KgGlobalData::ms_upsAlmStrategy.diOverName);
            }
            m_upsAlarmCount = 0;
            m_upsAlarm = 0;
        }
        KgGlobalData::ms_pStack->aEnvTemp[16] = m_upsAlarm;
    }
}

void DryCtrlThread::judgeDoorAlarm()
{
    if (KgGlobalData::ms_doorAlmStrategy.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_doorAlmStrategy, KgGlobalData::ms_dryData.DIVal, 8, strPos))
        {
            if(++m_doorAlarmCount >= KgGlobalData::ms_doorAlmStrategy.confirmedCount)
            {
                if (0 == m_doorAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_doorAlmStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_doorAlarm = 1;
                sendLog(0, QString("******************Door Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_doorAlarmCount);
        }
        else
        {
            if (1 == m_doorAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_doorAlmStrategy.diOverName);
            }
            m_doorAlarmCount = 0;
            m_doorAlarm = 0;
        }
        //sendLog(0, QString("******************aAcceCtrlState:%1").arg((int)KgGlobalData::ms_pStack->aAcceCtrlState));
        KgGlobalData::ms_pStack->aAcceCtrlState = m_doorAlarm;       // 门禁状态
    }
}

void DryCtrlThread::judgeDoorAlarmSec()
{
    if (KgGlobalData::ms_doorAlmStrategySec.diList.size() > 0)
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_doorAlmStrategySec, KgGlobalData::ms_dryData.DIVal, 8, strPos))
        {
            if(++m_doorAlarmCountSec >= KgGlobalData::ms_doorAlmStrategySec.confirmedCount)
            {
                if (0 == m_doorAlarmSec)
                {
                    saveLogToBaDb(KgGlobalData::ms_doorAlmStrategySec.diName + QString("(DI%1).").arg(strPos));
                }
                m_doorAlarmSec = 1;
                sendLog(0, QString("******************2# Door Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_doorAlarmCountSec);
        }
        else
        {
            if (1 == m_doorAlarmSec)
            {
                saveLogToBaDb(KgGlobalData::ms_doorAlmStrategySec.diOverName);
            }
            m_doorAlarmCountSec = 0;
            m_doorAlarmSec = 0;
        }
        //writeKgLogfile(QString("||||||||||||||||aStackTemp[4]=====:%1").arg((int)KgGlobalData::ms_pStack->aStackTemp[4]));
        //KgGlobalData::ms_pStack->aStackTemp[4] = m_doorAlarmSec;       // 门禁状态2
        KgGlobalData::ms_pStack->aEnvTemp[10] = m_doorAlarmSec;
    }
}

void DryCtrlThread::judgeObj(XFStrategy &obj, quint16 usDIVal, quint16 &alarmCount, quint16  &alarmState, QString strName)
{
    QString strPos;

    if(obj.diList.size() > 0)
    {
        if (HasAlarmVal(obj, usDIVal, 7, strPos))
        {
            if(++alarmCount >= obj.confirmedCount)
            {
                if (0 == alarmState)
                {
                    saveLogToBaDb(obj.diName + QString("(DI%1).").arg(strPos));
                }
                alarmState = 1;
                sendLog(0, QString("******************%1(DI%2)").arg(strName).arg(strPos));
            }

            limitAlmCount(alarmCount);
        }
        else
        {
            if (1 == alarmState)
            {
                saveLogToBaDb(obj.diOverName);
            }
            alarmCount = 0;
            alarmState = 0;
        }
    }
}

void DryCtrlThread::judgeAcFault()
{
    judgeObj(KgGlobalData::ms_acFaultStrategy, KgGlobalData::ms_dryData.DIVal, m_acFaultCount,
             m_acFault, "AC Fault");
}

void DryCtrlThread::judgeLqFault()
{
    judgeObj(KgGlobalData::ms_lqFaultStrategy, KgGlobalData::ms_dryData.DIVal, m_lqFaultCount,
             m_lqFault, "LQ Fault");
}

void DryCtrlThread::judgeBmsSmokeAlarm()
{
    judgeObj(KgGlobalData::ms_bmsSmokeStrategy, KgGlobalData::ms_dryData.DIVal, m_bmsSmokeCount,
             m_bmsSmokeAlarm, "Smoke alarm");
    if (KgGlobalData::ms_bmsSmokeStrategy.diList.size() > 0)
    {
        KgGlobalData::ms_pStack->aEnvTemp[23] = m_bmsSmokeAlarm;
    }
}

void DryCtrlThread::judgeBmsHeatAlarm()
{
    judgeObj(KgGlobalData::ms_heatSenseStrategy, KgGlobalData::ms_dryData.DIVal, m_bmsHeatCount,
             m_bmsHeatAlarm, "Heat alarm");
    if (KgGlobalData::ms_heatSenseStrategy.diList.size() > 0)
    {
        KgGlobalData::ms_pStack->aEnvTemp[24] = m_bmsHeatAlarm;
    }
}

// 判断备用信号是否有跳机信    号
char DryCtrlThread::hasResBreakAlarm()
{	
    char breakState = 0;
    for(int index = 0; index < RES_STRATEGY_COUNT; ++index)
    {
        XFStrategy &resStg = KgGlobalData::ms_resStrategy[index];
        if (resStg.diList.size() > 0)
        {
            if(resStg.iNeedBreak > 0) // 此信号触发需要跳机
            {
                if(1 == KgGlobalData::ms_pStack->aEnvTemp[index])
                {
                    printf("*****************aEnvTemp[%d]:%d, break system.\n", index, KgGlobalData::ms_pStack->aEnvTemp[index]);
                    breakState = 1;
                }
            }
        }
    }

    return breakState;
}

// 2023-11-11 整理处理8个备用信号合并成1个
void DryCtrlThread::judgetResState()
{
    for(int index = 0; index < RES_STRATEGY_COUNT; ++index)
    {
        XFStrategy &resStg = KgGlobalData::ms_resStrategy[index];
        if (resStg.diList.size() > 0)
        {
            QString strPos;
            if (HasAlarmVal(resStg, KgGlobalData::ms_dryData.DIVal, 8, strPos))
            {
                m_reservedCount[index] += 1;
                if(m_reservedCount[index] >= KgGlobalData::ms_doorAlmStrategy.confirmedCount)
                {
                    if (0 == m_reservedAlarm[index])
                    {
                        //if(isChLang())
                        //saveLogToBaDb(kgConvert("#1备用信号告警(DI%1).").arg(strPos));
                        //else
                        //saveLogToBaDb(kgConvert("Resvered alarm1(DI%1).").arg(strPos));
                        saveLogToBaDb(resStg.diName + QString("(DI%1).").arg(strPos));
                    }
                    m_reservedAlarm[index] = 1;
                    sendLog(0, QString("******************Reserved Alarm%1(DI%2)").arg(index+1).arg(strPos));
                }

                limitAlmCount(m_reservedCount[index]);
            }
            else
            {
                if (1 == m_reservedAlarm[index])
                {
                    //if(isChLang())
                    //saveLogToBaDb(kgConvert("#1备用信号告警结束(DI%1).").arg(strPos));
                    //else
                    //saveLogToBaDb(kgConvert("Resvered alarm1 over."));
                    saveLogToBaDb(resStg.diOverName);
                }
                m_reservedCount[index] = 0;
                m_reservedAlarm[index] = 0;
            }
            KgGlobalData::ms_pStack->aEnvTemp[index] = m_reservedAlarm[index];
        }
    }
}

void DryCtrlThread::judgeExtState()
{
    for(int index = 0; index < EXT_STRATEGY_COUNT; ++index)
    {
        XFStrategy &resStg = KgGlobalData::ms_extStrategy[index];
        if (resStg.diList.size() > 0)
        {
            QString strPos;
            if (HasAlarmVal(resStg, KgGlobalData::ms_dryData.DIVal, 8, strPos))
            {
                m_extCount[index] += 1;
                if(m_extCount[index] >= KgGlobalData::ms_doorAlmStrategy.confirmedCount)
                {
                    if (0 == m_extAlarm[index])
                    {
                        saveLogToBaDb(resStg.diName + QString("(DI%1).").arg(strPos));
                    }
                    m_extAlarm[index] = 1;
                    sendLog(0, QString("******************Extend Alarm%1(DI%2)").arg(index+1).arg(strPos));
                }

                limitAlmCount(m_extCount[index]);
            }
            else
            {
                if (1 == m_extAlarm[index])
                {
                    saveLogToBaDb(resStg.diOverName);
                }
                m_extCount[index] = 0;
                m_extAlarm[index] = 0;
            }
            //KgGlobalData::ms_pStack->aEnvTemp[index] = m_extAlarm[index];
        }
    }
}

// added 2021-12-28
// 判断是否有可燃气体信号，如有BAMS立即停机
bool DryCtrlThread::hasCombusGasAlarm()
{
    bool bEnabledAlarm = false; // 不使能 云浮1期只需将可燃气体信号传给后台，BA不需要做逻辑

    if(bEnabledAlarm)
    {
        return m_combusGasAlarm;
    }
    else
    {
        return 0;
    }
}

void DryCtrlThread::judgeCombusGasAlarm()
{

    if (KgGlobalData::ms_combusGasStrategy.diList.size() > 0) // 有采集可燃气体信号
    {
        QString strPos;
        if (HasAlarmVal(KgGlobalData::ms_combusGasStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_combusGasCount >= KgGlobalData::ms_combusGasStrategy.confirmedCount)
            {
                if (0 == m_combusGasAlarm)
                {
                    saveLogToBaDb(KgGlobalData::ms_combusGasStrategy.diName + QString("(DI%1).").arg(strPos));

                }
                //if (999 == KgGlobalData::ms_pStack->usFireBankAddr)
                //    m_combusGasAlarm  = 1;
                //else
                //	 m_combusGasDetectAlarm = 1;
                m_combusGasAlarm  = 1;
                sendLog(0, QString("******************Combustible Gas Alarm(DI%1)").arg(strPos));
            }

            limitAlmCount(m_combusGasCount);
        }
        else
        {
            if (1 == m_combusGasAlarm)
            {
                saveLogToBaDb(KgGlobalData::ms_combusGasStrategy.diOverName);
            }
            m_combusGasCount = 0;
            m_combusGasAlarm = 0;
            m_combusGasDetectAlarm = 0;
            m_combusGasSignal = 0;
        }

        KgGlobalData::ms_pStack->aGasAlarm = m_combusGasAlarm;        // 可燃气体
    }
}

quint16 DryCtrlThread::getIsolSwitchAggrState()
{
    // 有配置隔离开关策略, 才检查隔离开关是否都闭合
    if(KgGlobalData::ms_isolSwitchStrategy.diList.size() == 0)
    {
        return 0;
    }

    int closedCount = 0;
    int openedCount = 0;
    int totalCount = 0;
    for(int k = 0; k < KgGlobalData::ms_isolSwitchStrategy.diList.size(); ++k)
    {
        if(isBankInStack(k)) // 第k簇投入
        {
            totalCount += 1;
            DI_STU diStu = KgGlobalData::ms_isolSwitchStrategy.diList[k];
            int maskVal = (1 << diStu.diIndex);
            int tmpState = 0;
            if(maskVal == (maskVal & KgGlobalData::ms_dryData.DIVal)) // 第k簇的隔离开关闭合
            {
                closedCount += 1;
                tmpState = 1;
            }
            else
            {
                openedCount += 1;
            }

            if (1 == KgGlobalData::ms_saveHlkgLog)
            {

            }
        }
    }

    if(closedCount > 0 && closedCount == totalCount) // 隔离开关都闭合
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

quint16 DryCtrlThread::getConfSwitchState()
{
    int iClosedCount = 0;
    int iOpenedCount = 0;
    int totalCount = 0;

    // 有采集汇流开关反馈, 才检查汇流开关是否都闭合
    if(KgGlobalData::ms_hlkgStrategy.diCfgList.size() == 0)
    {
        return 0;
    }

    for(int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        DI_STU diStu = KgGlobalData::ms_hlkgStrategy.diCfgList[k];
        int tmpState = getConfSwitchState(KgGlobalData::ms_pStack, diStu);

        totalCount += 1;

        if(1 == tmpState)
        {
            iClosedCount += 1;
        }
        else
        {
            iOpenedCount += 1;
        }
    }

    if(iClosedCount > 0 && iClosedCount == totalCount)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void DryCtrlThread::judgetConfSwitchState(CBattStack *pStack)
{
    int iClosedCount = 0;
    int iOpenedCount = 0;
    int totalCount = 0;

    if(0 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
    {
#ifdef WOLONG_FUJIAN_PRJ 
        // 两个隔离开关都闭合才认为闭合 // added 2024-12-13
        if(pStack->aEnvTemp[2] > 0 && pStack->aEnvTemp[3] > 0)
        {
            pStack->usConfSwitchState = 1;//通知BA 汇流开关已经闭合
            pStack->aConfSwitchState = 1;
        }
        else
        {
            pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
            pStack->aConfSwitchState = 0;
        }
#endif
        return;
    }

    // 有采集汇流开关反馈, 才检查汇流开关是否都闭合
    // deleted 2022-3-26
    //if(KgGlobalData::ms_hlkgStrategy.diCfgList.size() == 0)
    //{
    //	return;
    //}

    //if (KgGlobalData::ms_hlkgStrategy.diCfg.diIndex < KgGlobalData::ms_devDiCount) // 有采集汇流开关反馈
    for(int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        DI_STU diStu = KgGlobalData::ms_hlkgStrategy.diCfgList[k];
        int tmpState = getConfSwitchState(pStack, diStu);

        totalCount += 1;

        //if (hlkgMask == (hlkgMask & g_DIState))   //DI1值为1，汇流开关闭合
        if(1 == tmpState)
        {
            sendLog(0, QString("***Hlkg%1 Has HZ.").arg(k+1));
            iClosedCount += 1;
            // modified 2022-7-11
            /*
            if(0 == k) // added 2022-05-25
                pStack->usDI1 = 1;
            else if(1 == k)
                pStack->usDI2 = 1;
            else if(2 == k)
                pStack->usDI3 = 1;
            else;
            */
            //pStack->usDI2 = 1;
        }
        else
        {
            sendLog(0, QString("***Hlkg%1 Has FZ.").arg(k+1));
            iOpenedCount += 1;
            /*
            if(0 == k) // added 2022-05-25
                pStack->usDI1 = 0;
            else if(1 == k)
                pStack->usDI2 = 0;
            else if(2 == k)
                pStack->usDI3 = 0;
            else;
            */
            //pStack->usDI2 = 0;
        }

        // 与BA主程序日志重复,汇流开关策略不是200时才输出 // modified 2022-11-18
        //if (1 == KgGlobalData::ms_saveHlkgLog && 200 != pStack->usConfSwitchStrategy)
        if (1 == KgGlobalData::ms_saveHlkgLog && 3 != pStack->usConfSwitchStrategy)
        {
            if ((0 == m_hlkgState[k]) && 1 == tmpState)     // || 99 == m_hlkgState
            {
                if(isChLang())
                {
                    //saveLogToBaDb(kgConvert("读取到串口继电器输入状态:%1.").arg(g_DIState));
                    if(1 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
                        saveLogToBaDb(kgConvert("汇流开关合闸."));
                    else
                        saveLogToBaDb(QString("%1#").arg(k+1) + kgConvert("汇流开关合闸."));
                }
                else
                {
                    //saveLogToBaDb(kgConvert("Read IO state:%1.").arg(g_DIState));
                    if(1 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
                        saveLogToBaDb(QString("ConfSwitch is closed."));
                    else
                        saveLogToBaDb(QString("%1# ConfSwitch is closed.").arg(k+1));

                }
            }
            else if((1 == m_hlkgState[k]) && 0 == tmpState) // || 99 == m_hlkgState
            {
                if(isChLang())
                {
                    //saveLogToBaDb(kgConvert("读取到串口继电器输入状态:%1.").arg(g_DIState));
                    if(1 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
                        saveLogToBaDb(kgConvert("汇流开关分闸."));
                    else
                        saveLogToBaDb(QString("%1#").arg(k+1) + kgConvert("汇流开关分闸."));
                }
                else
                {
                    //saveLogToBaDb(kgConvert("Read IO state:%1.").arg(g_DIState));
                    if(1 == KgGlobalData::ms_hlkgStrategy.diCfgList.size())
                        saveLogToBaDb(kgConvert("ConfSwitch is opened."));
                    else
                        saveLogToBaDb(QString("%1# ConfSwitch is opened.").arg(k+1));
                }
            }
            else
                ;
        }

        m_hlkgState[k] = tmpState;
    }

    if(iClosedCount > 0 && iClosedCount == totalCount)
    {
#ifdef MASTER_VER
        //if (3 == pStack->usConfSwitchStrategy)// 汇流开关策略 200 - 3rd进程设定 汇流开关断开,才能闭合接触器 // deleted 2023-12-13
        {
            pStack->usConfSwitchState = 1;//通知BA 汇流开关已经闭合
            pStack->aConfSwitchState = 1;
        }
        //pStack->usDI2 = 1;// deleted 2022-11-16
#else
        keepContCtrlOpened(pStack->usStackState,1);
#endif
        //pStack->usStackTemp[2] = 1; // 堆级断路器状态反馈信号 0--断开 1--闭合
    }
    else
    {
#ifdef MASTER_VER
        //if (3 == pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
            pStack->aConfSwitchState = 0;
        }
        //pStack->usDI2 = 0; // deleted 2022-11-16
        //pStack->usStackTemp[2] = 0; // 堆级断路器状态反馈信号 0--断开 1--闭合
#else
        keepContCtrlOpened(pStack->usStackState,0);
#endif	
    }
}

int g_isolSwitchClosedSignal = 0;
int g_isolSwitchOpenedSignal = 0;
int g_oldIsolSwitchAggrState = 99;
void DryCtrlThread::judgeIsolSwitchAggrState()
{
#ifdef LSZH_PRJ  //added 2021-5-13
    if ((0x0F & KgGlobalData::ms_dryData.DIVal) == 0x0) // 4个断路器都没有脱扣
    {
        m_emergStopAlarm = 0;
    }
    else // 有断路器脱扣
    {
        if (m_emergStopCount < 1000)
        {
            m_emergStopCount += 1;
        }

        if(m_emergStopCount >= 16) // 断路器断开维持20秒
        {
            if(0 == m_emergStopAlarm)
            {
                sprintf(m_tmpBuf,"检测到断路器脱扣(%d)，控制系统急停!", KgGlobalData::ms_dryData.DIVal);
                saveLogToBaDb(kgConvert(m_tmpBuf));
                m_emergStopAlarm = 1; // 通过急停告之BA跳机
            }
        }
    }
#endif

    // 有配置隔离开关策略, 才检查隔离开关是否都闭合
    if(KgGlobalData::ms_isolSwitchStrategy.diList.size() == 0)
    {
        return;
    }
    KgGlobalData::ms_pStack->usIsolSwitchStrategy = 200; // added 2024-6-8

    int closedCount = 0;
    int openedCount = 0;
    int totalCount = 0;
    for(int k = 0; k < KgGlobalData::ms_isolSwitchStrategy.diList.size(); ++k)
    {
        if(isBankInStack(k)) // 第k簇投入
        {
            totalCount += 1;
            DI_STU diStu = KgGlobalData::ms_isolSwitchStrategy.diList[k];
            int maskVal = (1 << diStu.diIndex);
            int tmpState = 0;
            if(maskVal == (maskVal & KgGlobalData::ms_dryData.DIVal)) // 第k簇的隔离开关闭合
            {
                closedCount += 1;
                tmpState = 1;
            }
            else
            {
                openedCount += 1;
            }

            if (1 == KgGlobalData::ms_saveHlkgLog)
            {
                if ((0 == m_glkgState[k]) && 1 == tmpState)     // || 99 == m_hlkgState
                {
                    if(isChLang())
                    {
                        if(1 == KgGlobalData::ms_isolSwitchStrategy.diList.size())
                            saveLogToBaDb(kgConvert("隔离开关闭合."));
                        else
                            saveLogToBaDb(QString("%1#").arg(k+1) + kgConvert("隔离开关闭合."));
                    }
                    else
                    {
                        if(1 == KgGlobalData::ms_isolSwitchStrategy.diList.size())
                            saveLogToBaDb(QString("IsolSwitch is closed."));
                        else
                            saveLogToBaDb(QString("%1# IsolSwitch is closed.").arg(k+1));

                    }
                }
                else if((1 == m_glkgState[k]) && 0 == tmpState)
                {
                    if(isChLang())
                    {
                        if(1 == KgGlobalData::ms_isolSwitchStrategy.diList.size())
                            saveLogToBaDb(kgConvert("隔离开关断开."));
                        else
                            saveLogToBaDb(QString("%1#").arg(k+1) + kgConvert("隔离开关断开."));
                    }
                    else
                    {
                        if(1 == KgGlobalData::ms_isolSwitchStrategy.diList.size())
                            saveLogToBaDb(QString("IsolSwitch is opened."));
                        else
                            saveLogToBaDb(QString("%1# IsolSwitch is opened.").arg(k+1));
                    }
                }
                else
                    ;
            }

            m_glkgState[k] = tmpState;
        }
    }

    if(closedCount > 0 && closedCount == totalCount) // 隔离开关都闭合
        //if(closedCount > 0) // 至少有一个隔离开关闭合
    {
        m_isolSwitchOpendCount = 0;
        g_isolSwitchOpenedSignal = 0;
        if(m_isolSwitchClosedCount < 1000)
        {
            m_isolSwitchClosedCount += 1;
        }
        if(m_isolSwitchClosedCount >= KgGlobalData::ms_isolSwitchStrategy.confirmedCount)
        {
            SetIsolSwitchAggrState(1);
            if(1 != g_oldIsolSwitchAggrState)// added 2021-07-17
            {
                g_oldIsolSwitchAggrState = 1;
                if(isChLang())
                    saveLogToBaDb(kgConvert("隔离开关闭合:") + QString("%1.").arg(KgGlobalData::ms_dryData.DIVal));
                else
                    saveLogToBaDb(QString("All IsolSwitch is closed:%1.").arg(KgGlobalData::ms_dryData.DIVal));
            }
        }
    }
    else
    {

        m_isolSwitchClosedCount = 0;
        g_isolSwitchClosedSignal = 0;
        if(m_isolSwitchOpendCount < 1000)
        {
            m_isolSwitchOpendCount += 1;
        }
        if(m_isolSwitchOpendCount >= KgGlobalData::ms_isolSwitchStrategy.confirmedCount)
        {
            SetIsolSwitchAggrState(0);
            if(0 != g_oldIsolSwitchAggrState)// added 2021-07-17
            {
                g_oldIsolSwitchAggrState = 0;
                if(isChLang())
                    saveLogToBaDb(kgConvert("隔离开关断开:") + QString("%1.").arg(KgGlobalData::ms_dryData.DIVal));
                else
                    saveLogToBaDb(QString("IsolSwitch is opened:%1.").arg(KgGlobalData::ms_dryData.DIVal));
            }
        }
    }
    /*
#ifdef GSHT_PRJ //added 2021-5-27
     int closedCount = 0;
     int openedCount = 0;
     for(int k = 0; k < 2; ++k) // 检查断路器1和2是否闭合
     {
        if(isBankInStack(0))
        {
            // 一直只判断第一簇，不对 现场测试只要第一簇合上，BA就会正常,这不对 2021-7-17
            if(1 == (1&g_DIState)) // 断路器闭合
            {
                closedCount += 1;
            }
            else
            {
                openedCount += 1;
            }
        }
    }

    if(closedCount > 0 && openedCount == 0) // 都闭合
    {
        SetIsolSwitchAggrState(1);
    }
    else
    {
        SetIsolSwitchAggrState(0);
    }
#endif
*/
}

void DryCtrlThread::judgeMainSwitchState()
{
    if (KgGlobalData::ms_mainSwitchStrategy.diList.size() > 0)
    {
        QString strPos;

        if (HasAlarmVal(KgGlobalData::ms_mainSwitchStrategy, KgGlobalData::ms_dryData.DIVal,1,strPos))
        {
            if (++m_mainSwitchCount >= KgGlobalData::ms_mainSwitchStrategy.confirmedCount)
            {
                if (0 == m_mainSwitchClosed)
                {
                    saveLogToBaDb(KgGlobalData::ms_mainSwitchStrategy.diName + QString("(DI%1).").arg(strPos));
                }
                m_mainSwitchClosed  = 1;
                sendLog(0, QString("******************Main switch is closed(DI%1)").arg(strPos));
            }

            limitAlmCount(m_mainSwitchCount);
        }
        else
        {
            if (1 == m_mainSwitchClosed)
            {
                saveLogToBaDb(KgGlobalData::ms_mainSwitchStrategy.diOverName);
            }

            m_mainSwitchCount = 0;
            m_mainSwitchClosed = 0;
        }

        KgGlobalData::ms_pStack->aEnvTemp[22] = m_mainSwitchClosed;
    }
}

void DryCtrlThread::judgeChgJcqState()
{
    if (KgGlobalData::ms_diIndexChgDrive < KgGlobalData::ms_devDiCount) // 有充电接触器反馈
    {
        int hlkgMask = 1 << KgGlobalData::ms_diIndexChgDrive;
        int newChgJcqState = 0;
        if (hlkgMask == (hlkgMask & KgGlobalData::ms_dryData.DIVal))//DI1值为1，汇流开关闭合
        {
            newChgJcqState = 1;// 充电接触器已经闭合
        }

        if(1 == newChgJcqState  && 0 == m_usOldChgJcqState)
        {
            if(isChLang())
                saveLogToBaDb(kgConvert("充电接触器闭合."));
            else
                saveLogToBaDb(QString("Charge contactor is closed."));
        }

        if(0 == newChgJcqState  && 1 == m_usOldChgJcqState)
        {
            if(isChLang())
                saveLogToBaDb(kgConvert("充电接触器断开."));
            else
                saveLogToBaDb(QString("Charge contactor is opened."));
        }

        m_usOldChgJcqState = newChgJcqState;
    }

    if (KgGlobalData::ms_diIndexDchgDrive < KgGlobalData::ms_devDiCount) // 有放电接触器反馈
    {
        int hlkgMask = 1 << KgGlobalData::ms_diIndexDchgDrive;
        int newDchgJcqState = 0;
        if (hlkgMask == (hlkgMask & KgGlobalData::ms_dryData.DIVal))
        {
            newDchgJcqState = 1;// 放电接触器已经闭合
        }

        if(1 == newDchgJcqState  && 0 == m_usOldDchgJcqState)
        {
            if(isChLang())
                saveLogToBaDb(kgConvert("放电接触器闭合."));
            else
                saveLogToBaDb(QString("Discharge contactor is closed."));
        }

        if(0 == newDchgJcqState  && 1 == m_usOldDchgJcqState)
        {
            if(isChLang())
                saveLogToBaDb(kgConvert("放电接触器断开."));
            else
                saveLogToBaDb(QString("Discharge contactor is opened."));
        }

        m_usOldDchgJcqState = newDchgJcqState;
    }
}

//读取DI1--DI6的状态并判断消防告警
int DryCtrlThread::readDevDIState(CBattStack *pStack, quint16 &connFailedCount)
{
    bool  bHasEmerStopStrategy = false;
    bool  bHasWaterStrategy = false;

    if (0 == m_pIOReader->readDevDIState(0,KgGlobalData::ms_dryData))//查询成功
    {
        if (KgGlobalData::ms_dryData.readDiCount < 100)
        {
            KgGlobalData::ms_dryData.readDiCount += 1;
        }
        /* deleted 2022-12-31
#ifdef ND_VER_PROGRAM   // 南都版本, 水浸由消防改变而来 2021-11-30  改xnview_zh.qm
        if (999 == pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4     紧急停机
        {
            bHasEmerStopStrategy = true;
        }
#else
        if (200 == pStack->usEmerStopStrategy)
        {
            bHasEmerStopStrategy = true;
        }

        if (999 == pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4
        {
            bHasWaterStrategy = true;
        }
#endif
*/
        //KgGlobalData::ms_dryData.bReadDiFlag = true;
        //printf("get DI1-6 state:%d\n", g_DIState);
        //处理读取到的DI信息 begin
        //printf("pStack->usFireBankAddr======================%d\n", pStack->usFireBankAddr);
        //if (999 == pStack->usFireBankAddr) // 999 - 接BA  消防接DI3 modified 2021-12-7
        {
            judgeXfAlarm();
            judgeXfSparyAlam();
            judgeXfFaultAlam();

            judgeXfAutoManu();
            judgeElecPowerOff();

            judgeCombusGasAlarm();
        }

        //if(bHasWaterStrategy)
        {
            judgeWaterAlarm();
            judgeWaterAlarmSec();
        }

        judgeThunderAlarm();
        judgeThunderAlarmSec();
        judgeFuseAlarm();
        judgeXfMotionMsg();
        judgeXfWarmMsg();
        judgeUpsAlarm();
        judgeDoorAlarm();
        judgeDoorAlarmSec();
        judgeAcFault();
        judgeLqFault();

        judgeBmsSmokeAlarm();
        judgeBmsHeatAlarm();

        judgetResState();
        judgeExtState();

        //if(bHasEmerStopStrategy)
        //{
        judgeEmergeStop();
        judgeEmergeStopSec();
        //}

        judgetConfSwitchState(KgGlobalData::ms_pStack);
        judgeIsolSwitchAggrState();
        judgeMainSwitchState();
        judgeChgJcqState();

        judgeBmsLocalState();
        judgeBmsRemoteState();

        // HZ alarm // added 2023-12-21
        if(KgGlobalData::ms_waterStrategy.diList.size() + KgGlobalData::ms_waterStrategySec.diList.size() > 0 ||
                has485WaterAlarm(1))
        {
            if(m_waterAlarm + m_waterAlarmSec + has485WaterAlarm(2) > 0)
                KgGlobalData::ms_pStack->aWaterAlarm = 1;
            else
                KgGlobalData::ms_pStack->aWaterAlarm = 0;
        }

        if(KgGlobalData::ms_emgStopStrategy.diList.size() + KgGlobalData::ms_emgStopStrategySec.diList.size() >0)
        {
            if(m_emergStopAlarm + m_emergStopAlarmSec > 0)// 发生急停
            {
                KgGlobalData::ms_pStack->usEmerStopState = 1;
                KgGlobalData::ms_pStack->aEmerStop = 1;
                writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
            }
            else
            {
                KgGlobalData::ms_pStack->usEmerStopState = 2;
                KgGlobalData::ms_pStack->aEmerStop = 0;
                writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(KgGlobalData::ms_pStack->usEmerStopState));
            }
        }

        if(g_runCount < 100)
            g_runCount += 1;
        //处理读取到的DI信息 end
    }

    return 0; // added 2023-11-9
}

quint16 DryCtrlThread::getConfSwitchState(CBattStack *pStack, DI_STU diStu)
{
    quint16 state = 0; // 记录汇流开关是否闭合

    //if (KgGlobalData::ms_hlkgStrategy.diCfg.diIndex < m_devDoCount)
    //{
    //int hlkgMask = 1 << KgGlobalData::ms_hlkgStrategy.diCfg.diIndex;
    int hlkgMask = 1 << diStu.diIndex;
    if(1 == diStu.alarmValue) // 检查到值为1（干结点闭合)表示汇流开关闭合  常用配置 modified 2021-06-22
    {
        if (hlkgMask == (hlkgMask & KgGlobalData::ms_dryData.DIVal))   //DI1值为1，汇流开关闭合
        {
            state = 1;//汇流开关已经闭合
        }
    }
    else // 检查到值为0（干结点断开)表示汇流开关闭合
    {
        if (hlkgMask != (hlkgMask & KgGlobalData::ms_dryData.DIVal))   //DI1值为0，汇流开关闭合
        {
            state = 1;//汇流开关已经闭合
        }
    }
    //}

    return state;
}

quint16 DryCtrlThread::getClosedConfSwitchCount()
{
    int closeCount = 0;

    for(int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        DI_STU diStu = KgGlobalData::ms_hlkgStrategy.diCfgList[k];
        if (getConfSwitchState(KgGlobalData::ms_pStack,diStu) > 0)
        {
            closeCount += 1;
        }
    }

    return closeCount;
}

QString DryCtrlThread::getConfSwitchStrState()
{
    QString strState;

    for(int k = 0; k < KgGlobalData::ms_hlkgStrategy.diCfgList.size(); ++k)
    {
        if(k > 0)
        {
            strState += QString("-");
        }
        strState += QString("%1").arg(m_hlkgState[k]);
    }

    return strState;
}


//跳机时驱动分闸
quint16 DryCtrlThread::waitFzOpt(quint16 ctrlType, quint16 &drvFzCount, quint16 &drvFzSuccedCount, QDateTime &drvFzTime, QDateTime statChangeTime)
{
    QString strLog;
    quint16 usDrvFz = 0;

    if (0 == drvFzCount)// 还没有发送分闸命令 // 第一次一定会下发，不管是否已经分闸
    {
        if(!statChangeTime.isValid())
        {
            statChangeTime = QDateTime::currentDateTime();
        }
        /*
        if (getHlKgState(pStack) == 0)//DI1为0, 电操已分闸 2020-2-22 added
        {
             QDateTime nowTime = QDateTime::currentDateTime();
             int elapseSec  = drvFzTime.secsTo(nowTime);
             if (drvFzTime.isValid() && elapseSec < 120)//120秒内不重复执行
             {
                 strLog = QString("drvFzCount:%1, waitFzOpt=====================================has FZ OK").arg(drvFzCount);
                 sendLog(0, strLog);
                 return 0;
             }
        }
        */

        int cirCount = 0;
        while(1) // 延时处理：在断开接触器之前4秒，先控制汇流开关分闸
        {
            if (++cirCount >= 3000)// 等待30秒还没有发送分闸命令，出错
            {
                strLog = QString("Try drive FZ failed**********.");
                sendLog(0, strLog);
                break;
            }
            if ((cirCount%100) == 0)
            {
                strLog = QString("WaitFzOpt ======== usDelayBeforeCutCntor:%1, wait time:%2S.")
                        .arg(KgGlobalData::ms_pStack->usDelayBeforeCutCntor).arg(cirCount*10/1000.0);
                sendLog(0, strLog);
            }

            QDateTime nowTime = QDateTime::currentDateTime();
            qint64 elapseSec = statChangeTime.msecsTo(nowTime);

            //QString strInfo = statChangeTime.toString("hh:mm:ss   ") + nowDateTime.toString("hh:mm:ss");
            //sendLog(0, strInfo);

            int waitTime = 0;
            if (KgGlobalData::ms_pStack->usDelayBeforeCutCntor > 4)
            {
                waitTime = KgGlobalData::ms_pStack->usDelayBeforeCutCntor-4;
            }

            if (elapseSec >= waitTime*1000)//故障发生超过Delay秒
            {
                drvFzCount += 1;
                usDrvFz = 1;//驱动分闸
                strLog = QString("WaitFzOpt ======== FZ, drvFzCount:%1.").arg(drvFzCount);
                sendLog(0, strLog);

                if(1 == ctrlType)
                {
                    //saveLogToBaDb(kgConvert("控制汇流开关分闸."));
                }
                else
                {
                    //saveLogToBaDb(kgConvert("EMS控制汇流开关分闸."));
                }
                if(isChLang())
                    saveLogToBaDb(kgConvert("控制汇流开关分闸."));
                else
                    saveLogToBaDb(QString("Control opening bus switch."));
                drvFzTime = nowTime;
                break;
            }
            this->msleep(10);
        }
    }
    else//已发送分闸命令
    {
        if(!drvFzTime.isValid())
        {
            drvFzTime = QDateTime::currentDateTime();
        }
        //if (getHlKgState(KgGlobalData::ms_pStack) > 0)// DI1为1,电操还没断开
        if(getClosedConfSwitchCount() > 0) // 电操还没断开
        {
            if(1 == drvFzSuccedCount) // 前面已经分闸，现在刚又检测到合闸
            {
                if(1 == ctrlType)
                {
                    //saveLogToBaDb(kgConvert("控制汇流开关分闸."));
                }
                else
                {
                    //saveLogToBaDb(kgConvert("EMS控制汇流开关分闸."));
                }
                if(isChLang())
                    saveLogToBaDb(kgConvert("控制汇流开关分闸."));
                else
                    saveLogToBaDb(QString("Control bus switch opening."));
            }
            drvFzSuccedCount = 0;
            //if (drvFzCount < 3)//最多只试3次 modified 2021-9-19
            //{
            QDateTime nowTime = QDateTime::currentDateTime();
            int elapseSec  = drvFzTime.secsTo(nowTime);
            strLog = QString("waitFzOpt================elapseSec:%1").arg(elapseSec);
            sendLog(0, strLog);

            if (elapseSec >= 2)//至少过2秒还没有响应，重新发送命令 //10  modified 2021-9-19
            {
                if(++drvFzCount >= 30000)
                {
                    drvFzCount = 20000;
                }

                if(drvFzCount < 150)  // 分闸不成功时，前5分钟每2秒操作一次
                {
                    usDrvFz = 1;//驱动分闸
                }
                else
                {
                    if(150 == drvFzCount)
                    {
                        if(isChLang())
                            saveLogToBaDb(kgConvert("控制汇流开关分闸失败."));
                        else
                            saveLogToBaDb(QString("Control opening bus switch failed."));
                    }
                    if((drvFzCount%8) == 0)// 分闸不成功时，5分钟后每16秒操作一次
                    {
                        usDrvFz = 1;//驱动分闸
                    }
                }

                strLog = QString("waitFzOpt================FZ, try drive FZ again, drvFzCount:%1, fzSuccedCount:%2.").arg(drvFzCount).arg(drvFzSuccedCount);
                sendLog(0, strLog);
                drvFzTime = nowTime;
            }
            //}
            //else//分闸失败
            //{
            //	 strLog = QString("WaitFzOpt ********** FZ failed.");
            //   sendLog(0, strLog);
            //}
        }
        else//已经分闸
        {
            strLog = QString("WaitFzOpt ======== has FZ OK, drvFzCount:%1, fzSuccedCount:%2.").arg(drvFzCount).arg(drvFzSuccedCount);
            sendLog(0, strLog);

            /*
            uchar index = 0;
            bool  bHasEmerStopStrategy = false;
            bool  bHasWaterStrategy = false;

            m_pDataBuf[index++] = 0x99;
            m_pDataBuf[index++] = 06;

            int regAddr = 0x5000;
            addParam2Buffer(m_pDataBuf+index, regAddr);// 起始地址:要查询的第一个光耦寄存器地址
            index += 2;

            int regVal = 0x1234;
            addParam2Buffer(m_pDataBuf+index, KgGlobalData::ms_devDiCount);// 寄存器个数:要查询的光耦寄存器数量
            index += 2;

            quint16 crcValue = Modbus_CRC16((uchar*)m_pDataBuf, index);
            addParam2Buffer(m_pDataBuf+index, crcValue);
            index += 2;

            int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, index);
            */

            drvFzCount = 1;

            if(drvFzSuccedCount < 2) // 执行成功后再操作分闸2次
            {
                drvFzSuccedCount += 1;
                usDrvFz = 1;//驱动分闸
                drvFzTime = QDateTime::currentDateTime();
            }
        }
    }

    return usDrvFz;
}

//驱动合闸
quint16 DryCtrlThread::waitHzOpt(quint16 ctrlType, quint16 &drvHzCount, QDateTime &drvHzTime)
{
    QString strLog;
    quint16 usDrvHz = 0;

    if (0 == drvHzCount)//还没有发送合闸命令
    {
        //控制第1个DO口闭合
        drvHzCount += 1;
        usDrvHz = 1;//驱动合闸
        sendLog(0, QString("WaitHzOpt ======== HZ, drvHzCount:%1.").arg(drvHzCount));

        if(1 == ctrlType)
        {
            //saveLogToBaDb(kgConvert("控制汇流开关合闸."));
        }
        else
        {
            //saveLogToBaDb(kgConvert("EMS控制汇流开关合闸."));
        }
        if(isChLang())
            saveLogToBaDb(kgConvert("控制汇流开关合闸."));
        else
            saveLogToBaDb(QString("Control bus switch closing."));
        drvHzTime = QDateTime::currentDateTime();
    }
    else//已发送合闸命令
    {
        //if (getHlKgState(KgGlobalData::ms_pStack) > 0)//DI1为1,电操已经合上 2020-2-22 added
        if(getClosedConfSwitchCount() < KgGlobalData::ms_hlkgStrategy.diCfgList.size())
        {
            QDateTime nowTime = QDateTime::currentDateTime();
            int elapseSec  = drvHzTime.secsTo(nowTime);
            if (drvHzTime.isValid() && elapseSec < 120)//120秒内不重复执行
            {
                sendLog(0, QString("WaitHzOpt ======== has HZ OK, drvHzCount:%1.").arg(drvHzCount));
                return 0;
            }
        }

        //if (getHlKgState(KgGlobalData::ms_pStack) == 0)//DI1为0, 电操还没合上
        if(getClosedConfSwitchCount() < KgGlobalData::ms_hlkgStrategy.diCfgList.size())
        {
            //if (drvHzCount < 3)//最多只试3次 modified 2021-9-19
            //{
            QDateTime nowDateTime = QDateTime::currentDateTime();
            int elapseSec  = drvHzTime.secsTo(nowDateTime);
            strLog = QString("waitHzOpt================elapseSec:%1").arg(elapseSec);
            sendLog(0, strLog);

            if (elapseSec >= 5)//至少过5秒还没有响应，重新发送命令// 10  modified 2021-9-19
            {
                drvHzCount += 1;
                usDrvHz = 1;//驱动合闸
                strLog = QString("waitHzOpt================HZ, try drive HZ again, drvHzCount:%1").arg(drvHzCount);
                sendLog(0, strLog);
                drvHzTime = nowDateTime;
            }
            //}
            //else //合闸失败
            //{
            //   //pStack->usStackTemp[27] = 0;

            //   KgGlobalData::ms_pStack->usStackTemp[12] = 0;

            //   strLog = QString("waitHzOpt ********** HZ failed");
            //   sendLog(0, strLog);
            //}
        }
        else //已经合闸, 修改合闸总次数，否则如果持续有合闸命令，但DI1突然变为0，则会继续发送合闸命令
        {
            //pStack->usStackTemp[27] = 0;
            KgGlobalData::ms_pStack->usStackTemp[12] = 0;

        }
    }

    return usDrvHz;
}

void DryCtrlThread::parseStackState(quint16 stackState, quint16 &usHasProt, quint16 &usHasAlarm,
                                    quint16 &usChargeFull, quint16 &usDischargeEmpty, quint16 &usProhibitChgDchg)
{	
    usHasProt = 0;
    usHasAlarm = 0;
    usChargeFull = 0;
    usDischargeEmpty = 0;
    usProhibitChgDchg = 0;

#ifdef MASTER_VER  // BA通用版本
    if (0xAAAA == stackState)
    {
        usHasProt = 1;
    }
    else if (0x5555 == stackState)
    {
        usHasAlarm = 1;
        usProhibitChgDchg = 1;
    }
    else if (0x1111 == stackState)
    {
        usChargeFull = 1;
        usHasAlarm = 1;
    }
    else if (0x2222 == stackState)
    {
        usDischargeEmpty = 1;
        usHasAlarm = 1;
    }
    else
        ;
#endif

#ifdef ND_VER_PROGRAM 		// 南都版本
    // 电池堆状态     0x1006    0 - 正常   1 - 禁充    2 - 禁放    3 - 待机     4 - 停机
    if (4 == stackState)
    {
        usHasProt = 1;
    }
    else if (3 == stackState)
    {
        usHasAlarm = 1;
        usProhibitChgDchg = 1;
    }
    else if (1 == stackState)
    {
        usChargeFull = 1;
        usHasAlarm = 1;
    }
    else if (2 == stackState)
    {
        usDischargeEmpty = 1;
        usHasAlarm = 1;
    }
    else
        ;
#endif
}

// 如果有断路器断开，则强制为保护告警  //added 2021-5-13
void DryCtrlThread::lszhParseDLQState(quint16 &usHasProt)
{
    //if(1 == g_bReadDiFlag)//if(KgGlobalData::ms_dryData.bReadDiFlag)
    if(KgGlobalData::ms_dryData.readDiCount > 0)
    {
        if ((0x0F & KgGlobalData::ms_dryData.DIVal) == 0x0) // 4个断路器都没有脱扣
        {
        }
        else // 有断路器脱扣
        {
            usHasProt = 1;
        }
    }
}

int isSystemError(int stackState)
{
    int isError = 0;

#ifdef MASTER_VER  // BA通用版本
    if (0xAAAA == stackState)
    {
        isError = 1;
    }
#endif

#ifdef ND_VER_PROGRAM 		// 南都版本
    if (4 == stackState)
    {
        isError = 1;
    }
#endif
    return isError;
}

// added 2022-6-30
bool hasSomeProt()
{
    bool iHasProt = false;

    for(int k = 0; k < KgGlobalData::ms_installBankNum; ++k)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);

        if(pBank && isBankInStack(k))
        {
            // 放电温度上限保护   单体电压下限保护   组电压下限保护
            if (pBank->aDchgTempUpLimitProt || pBank->aSglVolDownLimitProt || pBank->aBankVolDownLimitProt)
            {
                iHasProt = true;
                break;
            }
        }
    }

    return iHasProt;
}

// 判断是否有合闸命令 added 2022-1-25
int hasEmsHzCmd(CBattStack *pStack)
{
    bool retResult = false;

#ifdef MASTER_VER  // BA通用版本
    if(1 == pStack->usEMSConfCtrl)
    {
        retResult = true;
    }
#endif

    return retResult;
}

// 判断是否有分闸命令
int hasEmsFzCmd(CBattStack *pStack)
{
    bool retResult = false;

#ifdef MASTER_VER  // BA通用版本
    if(2 == pStack->usEMSConfCtrl)
    {
        retResult = true;
    }
#endif

    return retResult;
}

void clearEmsCmd(CBattStack *pStack)
{
#ifdef MASTER_VER  // BA通用版本
    pStack->usEMSConfCtrl = 0;
#endif
}

quint16 DryCtrlThread::hasEmertStopAlarm()
{
    quint16 retResult = 0;
#ifdef MASTER_VER  // BA通用版本
    // 紧急停机状态             0 - 默认  1 - 告警  2 - 正常
    // modified 2022-05-27
    //if(1 == KgGlobalData::ms_pStack->usEmerStopState || m_emergStopAlarm > 0)
    if((m_emergStopAlarm + m_emergStopAlarmSec) > 0)
    {
        retResult = 1;
    }
#else
    if(m_emergStopAlarm > 0)
    {
        retResult = 1;
    }
#endif

    return retResult;// m_emergStopAlarm;
}

quint16  DryCtrlThread::hasFireAlarm()
{
    return m_fireAlarm;
}

quint16 DryCtrlThread::hasWaterAlarm() // added 2024-11-7
{
    quint16 retResult = 0;

    if(m_waterAlarm + m_waterAlarmSec + has485WaterAlarm(2) > 0)
    {
        retResult = 1;
    }

    return retResult;
}

bool DryCtrlThread::isAllBankFault()
{
    int faultCount = 0;
    bool isAllFault = false;
    for(int grp = 0; grp < KgGlobalData::ms_installBankNum; ++grp)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(grp);
        if (!pBank)
        {
            continue;
        }

        if(0xAAAA == pBank->usBankState)
        {
            faultCount += 1;
        }
    }

    if(faultCount == KgGlobalData::ms_installBankNum)
    {
        isAllFault = true;
    }

    return isAllFault;
}

bool DryCtrlThread::isRemoteMode() // added 2024-5-4
{
    bool isRemote = true; // 默认为远程模式

    //if (0 == m_bmsLocalState &&  1 == m_bmsRemoteState)
    //{
    //}

    // 远方模式时，才接收合闸命令 // added 2024-5-4
    if (KgGlobalData::ms_bmsLocalStrategy.diList.size() > 0 && m_bmsLocalState > 0)
    {
        isRemote = false;
    }

    if(KgGlobalData::ms_bmsRemmoteStrategy.diList.size() > 0 && 0 == m_bmsRemoteState)
    {
        isRemote = false;
    }

    return isRemote;
}

int g_oldHlkgHzCount = 0;
bool DryCtrlThread::controlHzFz()
{
    quint16   usDrvFz = 0;    //是否驱动分闸
    quint16   usDrvHz = 0;    //是否驱动合闸
    QString strHint;
    int doIndex = 0;
    int k;

    CBattStack *pStack = KgGlobalData::ms_pStack;

    // step3. 判断是否需要分闸合闸操作
    //quint16   usDrvFz = 0;    //是否驱动分闸
    //quint16   usDrvHz = 0;    //是否驱动合闸
    int needBreakCnt = NeedBreakJCQCount();
    int needCloseCnt = NeedCloseJCQCount();
    int closedCnt = GetClosedJCQCount();
    int openedCnt = GetOpenedJCQCount();
    // 平高昆山usStackTemp[27], 许继江虹变usStackTemp[12] 27
    // quint16 emsCtrlHz = pStack->usStackTemp[27];//EMS控制的合闸分闸信号
    // pStack->usStackTemp[27] = 0;

    quint16 emsCtrlHz  = 0;
    quint16 tmpCmd  = 0;
    quint16 hasUsed = 0;

#ifdef ND_HNXJ	// added 2022-10-12
    hasUsed = true; // usStackTemp[27]已被使用
#endif

#ifdef HJ_5MWH	
    hasUsed = true; // usStackTemp[27]已被使用
#endif

    if(!hasUsed)
    {
        if (isRemoteMode())// 远方模式时，才接收命令 // added 2024-5-4
        {
            tmpCmd = pStack->usStackTemp[27];//EMS控制的合闸分闸信号, 1-上电, 2-下电
            pStack->usStackTemp[27] = 0;
        }
    }

#ifdef ND_VER_PROGRAM	
    if(1 == tmpCmd)     // 上电命令
    {
        // 并网连接状态  1 - 启动(Start Connection);  2 - 成功(Connection Successful);  3 - 结束(Process End)；
        if (2 == pStack->usConnState)  //  并网后才接收上电命令
        {
            emsCtrlHz = 1;
        }
        else
        {
            strHint = QString("***********************ND Ver, usConnState:%1, refuse to connect.").arg(pStack->usConnState);
            sendLog(0, strHint);
        }
    }
    else if(2 == tmpCmd)// 下电命令
    {
        emsCtrlHz = 2;
    }
    else
        ;
    if(m_oldConnState != pStack->usConnState)
    {
        m_drvHzCount = 0;
    }
    m_oldConnState = pStack->usConnState;
    strHint = QString("***********************ND Ver data, usConnState:%1, emsCtrlHz:%2.").arg(pStack->usConnState).arg(emsCtrlHz);
    sendLog(0, strHint);
#else
    emsCtrlHz = tmpCmd;
    strHint = QString("=============emsCtrlHz:%1, usEMSContCtrl:%2, usEMSConfCtrl:%3.")
            .arg(emsCtrlHz).arg(pStack->usEMSContCtrl).arg(pStack->usEMSConfCtrl);  // 堆接触器管理  // 汇流开关管理
    sendLog(0, strHint);
#endif
    strHint = QString("NeedBreakCnt:%1, needCloseCnt:%2, closedCnt:%3, openedCnt:%4, emsCtrlHz:%5.")
            .arg(needBreakCnt).arg(needCloseCnt).arg(closedCnt).arg(openedCnt).arg(emsCtrlHz);
    sendLog(0, strHint);

    if(isSystemError(m_stackState))
    {
        g_masterHZCmd = 0;
    }

    // 1.BA故障时主动分闸  ************************************************
    if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // 有分闸干结点
    {
        // 2022-01-09 (1)实现急停和消防时立刻断开汇流开关；(2)断开失败时不断重试分闸;(3)操作成功时再执行一次。
        //if( 1 == m_fireAlarm || 1 == m_waterAlarm) // 有 急停 或 消防告警
        //if(hasEmertStopAlarm() || 1 == m_fireAlarm || 1 == m_fireSprayAlarm || 1 == m_waterAlarm) // 有 急停 或 消防告警
        char xfWarnFz = 0;
        char xfAlarmFz = 0; // added 2024-4-27
        char waterAlarmFz = 0;
        if(KgGlobalData::ms_xfWarnFzEnabled > 0 && 1 == m_xfWarmMsg)
        {
            xfWarnFz = 1;
        }
        if(KgGlobalData::ms_xfAlarmFzEnabled > 0 && 1 == m_fireAlarm)
        {
            xfAlarmFz = 1;
        }
        if(KgGlobalData::ms_waterAlarmFzEnabled > 0 && 1 == m_waterAlarm)
        {
            waterAlarmFz = 1;
        }

        if(hasEmertStopAlarm() || ((xfWarnFz + xfAlarmFz + waterAlarmFz) > 0) || 1 == m_fireSprayAlarm)
        {
            if(1 != m_usOldEmerStopState && hasEmertStopAlarm()) // 刚发生急停，需要立马断开汇流开关，不延时 added 2022-1-6
            {
                if(getClosedConfSwitchCount() > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("急停,分闸汇流开关."));
                    else
                        saveLogToBaDb(kgConvert("Emergency, open bus switch."));
                }
                m_drvFzCount = 1;
                m_drvFzSuccedCount = 0;
                usDrvFz = 1;
                m_drvFzTime = QDateTime::currentDateTime();
                if(0 == getClosedConfSwitchCount())
                {
                    //m_drvFzSuccedCount = 1;
                }
            }
            else if(0 == m_oldFireAlarm && 1 == m_fireAlarm)      // 刚发生消防，需要立马断开汇流开关，不延时 added 2022-1-6
            {
                if(getClosedConfSwitchCount() > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防告警,分闸汇流开关."));
                    else
                        saveLogToBaDb(QString("Fire alarm, open bus switch."));
                }
                m_drvFzCount = 1;
                m_drvFzSuccedCount = 0;
                usDrvFz = 1;
                m_drvFzTime = QDateTime::currentDateTime();
                if(0 == getClosedConfSwitchCount())
                {
                    //m_drvFzSuccedCount = 1;
                }
            }
            else if(0 == m_oldFireSprayAlarm && 1 == m_fireSprayAlarm)      // 刚发生消防，需要立马断开汇流开关，不延时 added 2022-1-6
            {
                if(getClosedConfSwitchCount() > 0)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("消防喷洒,分闸汇流开关."));
                    else
                        saveLogToBaDb(QString("Fire spray, open bus switch."));
                }
                m_drvFzCount = 1;
                m_drvFzSuccedCount = 0;
                usDrvFz = 1;
                m_drvFzTime = QDateTime::currentDateTime();
                if(0 == getClosedConfSwitchCount())
                {
                    //m_drvFzSuccedCount = 1;
                }
            }
            else
            {
                /*
                if(0 == g_oldHlkgHzCount && getClosedConfSwitchCount() > 0) // 汇流开关还合上
                {
                    m_drvFzCount = 1;
                    usDrvFz = 1;
                    saveLogToBaDb(kgConvert("检测到汇流开关合闸,强制分闸."));
                }*/
                usDrvFz = waitFzOpt(1, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
            }
        }
        else if (isSystemError(m_stackState) &&  needBreakCnt > 0)// BA故障，消防和急停时，驱动分闸
        {
            usDrvFz = waitFzOpt(1, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
        }
#ifdef  YW0357_PRJ
        else if ((0x5555 == pStack->usStackState || 0x2222 == pStack->usStackState) &&
                 hasSomeProt())// BA禁放，放电温度上限保护 或 单体电压下限保护时，驱动分闸   // added 2022-6-30
        {
            usDrvFz = waitFzOpt(1, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
        }
#endif
        /*else if(1 == m_fireAlarm || 1 == m_emergStopAlarm) // 再判断一下会更好，保证消防和急停时会驱动分闸 added 2021-9-19
        {
            m_statChangeTime = QDateTime::currentDateTime();
            usDrvFz = waitFzOpt(m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);
        }
        */
        else
            ;
        m_usOldEmerStopState = hasEmertStopAlarm();
        m_oldFireAlarm = m_fireAlarm;
        m_oldFireSprayAlarm = m_fireSprayAlarm;
    }

    g_oldHlkgHzCount = getClosedConfSwitchCount();

    // 2.检测异常情况，有必要时主动分闸  ************************************************
    // added 2020-5-21 检测接触器断开,但汇流开关合闸状态，如有过30秒主动分闸
    if (0 == usDrvFz && 0 == usDrvHz && KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0) // 当前没有驱动合闸分闸
    {
        //if(openedCnt > 0 && (getHlKgState(pStack) > 0))// 有接触器断开，汇流开关还处于合闸状态
        if(openedCnt > 0 && (getClosedConfSwitchCount() > 0))
        {
            m_detectYcCount += 3; // 先计时
            sendLog(0, QString("Step501 detectYcCount:%1.").arg(m_detectYcCount));
        }
        else // 数据清0
        {
            m_detectYcCount = 0;
            m_masterFzCount = 0;
            sendLog(0, QString("Step502 clear detectYcCount."));
        }

        if (m_detectYcCount >= 30*4) // 维持30秒后，主动进行分闸
        {
            if (m_masterFzCount < 1) // 只下发1次

            {
                usDrvFz = 1;
                m_masterFzCount += 1;
                sendLog(0, QString("***Master FZ."));
                if(isChLang())
                {

                    saveLogToBaDb(kgConvert("接触器已断开,强制分闸汇流开关."));
                }
                else
                {
                    saveLogToBaDb("Contactor has been opened, opening bus switch.");
                }
            }
        }
    }

    // 3.配置为自动合闸时，接触器都闭合后主动合闸  ************************************************
    // aEnvTemp[49]：1-EMS控制汇流开关合闸 0-BMS控制汇流开关合闸
    if (1== KgGlobalData::ms_hzEnabled && 0 == usDrvFz && 0 == usDrvHz && 0 == m_pStack->aEnvTemp[49] &&
            KgGlobalData::ms_hlkgStrategy.hzDoList.size() > 0 && KgGlobalData::ms_bankNumInStack > 0) // 当前没有驱动合闸分闸
    {
        if (0 == m_fireAlarm && 0 == hasEmertStopAlarm())
        {
            // 所有电池组接触器都闭合, 汇流开关还处于分闸状态
            // if(closedCnt >= KgGlobalData::ms_bankNumInStack && (getHlKgState(pStack) == 0))
            // added 2024-5-4 added (0 == m_bmsLocalState &&  1 == m_bmsRemoteState)
            if(!isSystemError(m_stackState) && isRemoteMode() &&
                    closedCnt >= KgGlobalData::ms_bankNumInStack && (getClosedConfSwitchCount() < KgGlobalData::ms_hlkgStrategy.diCfgList.size()))
            {
                m_detectOkCount += 3; // 先计时
                sendLog(0, QString("Step503 detectOkCount:%1.").arg(m_detectOkCount));
            }
            // added 2024-4-26 修改没有汇流开关反馈节点时，也可以自动控制合闸
            else if(!isSystemError(m_stackState) && isRemoteMode() &&
                    closedCnt >= KgGlobalData::ms_bankNumInStack && (0 == g_masterHZCmd && 0 == KgGlobalData::ms_hlkgStrategy.diCfgList.size()))
            {
                m_detectOkCount += 3; // 先计时
                sendLog(0, QString("Step503 detectOkCount:%1.").arg(m_detectOkCount));
            }
            else // 数据清0
            {
                m_detectOkCount = 0;
                m_masterHzCount = 0;
                sendLog(0, QString("Step504 clear detectOkCount."));
            }

            //if (m_detectOkCount >= 15) // 维持15秒后，主动进行合闸
            //if (m_detectOkCount >= 30) // 维持15秒后，主动进行合闸
            if (m_detectOkCount >= 90) // 维持15秒后，主动进行合闸
            {
                m_detectOkCount = 0;

                if (m_masterHzCount < 3) // 只下发3次

                {
                    g_masterHZCmd = 1;
                    usDrvHz = 1;
                    m_masterHzCount += 1;
                    sendLog(0, QString("***Master HZ."));
                    if(1 == m_masterHzCount)
                    {
                        if(isChLang())
                        {

                            saveLogToBaDb(kgConvert("接触器已闭合,强制合闸汇流开关."));
                        }
                        else
                        {
                            saveLogToBaDb("Contactor has been closed, closing bus switch.");
                        }
                    }
                }
            }

        }
    }
    //added end

    // 4.接受EMS的合闸分闸命令  ************************************************
    if (0 == usDrvFz && 0 == usDrvHz) // 当前没有驱动合闸分闸
    {
        if (1 == emsCtrlHz || hasEmsHzCmd(pStack)) //驱动合闸 // || 1 == pStack->usEMSConfCtrl
        {
            if(hasEmsHzCmd(pStack))//if(1 == pStack->usEMSConfCtrl) // added 2022-1-19
            {
                clearEmsCmd(pStack);//  pStack->usEMSConfCtrl = 0;
            }

            for(int k = 0; k < 10; ++k)
            {
                sendLog(0, QString("============================================1Recv HZ cmd from EMS."));
            }

            if(!isSystemError(m_stackState) && closedCnt >= KgGlobalData::ms_bankNumInStack) // 无故障，且所有电池组接触器都闭合
            {
                //sendLog(0, QString("=====Recv HZ cmd from EMS."));
                for(int k = 0; k < 10; ++k)
                {
                    sendLog(0, QString("============================================2Recv HZ cmd from EMS."));
                }
                usDrvHz = 1;//驱动合闸
                //usDrvHz = waitHzOpt(2, m_drvHzCount, m_drvHzTime);

                if (m_saveEmsCtrlHzRdCount < 5)
                {
                    m_saveEmsCtrlHzRdCount += 1;
                    if(1 == emsCtrlHz)
                    {
                        if(isChLang())
                            saveLogToBaDb(kgConvert("远程控制合闸."));
                        else
                            saveLogToBaDb(QString("Remote closing bus switch."));
                    }
                    else
                    {
                        if(isChLang())
                            saveLogToBaDb(kgConvert("远程控制合闸(BMS控制)."));
                        else
                            saveLogToBaDb(QString("Remote closing bus switch(BMS control)."));
                    }
                }
            }
            else  // 有电池组接触器没有闭合，拒绝合闸命令
            {
                sendLog(0, QString("=====Reject HZ cmd from EMS."));
                if (m_saveRejectEmsHzRdCount < 5)
                {
                    m_saveRejectEmsHzRdCount += 1;
                    if(1 == emsCtrlHz)
                    {
                        if(isChLang())
                            saveLogToBaDb(kgConvert("条件不具备，拒绝远程合闸."));
                        else
                            saveLogToBaDb(QString("Reject remote closing bus switch."));
                    }
                    else
                    {
                        if(isChLang())
                            saveLogToBaDb(kgConvert("条件不具备，拒绝远程合闸(BMS控制)."));
                        else
                            saveLogToBaDb(QString("Reject remote closing bus switch(BMS control)."));
                    }
                }
            }
        }
        else if (2 == emsCtrlHz || hasEmsFzCmd(pStack))//驱动分闸 // || 2 == pStack->usEMSConfCtrl
        {
            //sendLog(0, QString("=====Recv FZ cmd from EMS."));
            if(hasEmsFzCmd(pStack))//if(2 == pStack->usEMSConfCtrl) // added 2022-1-19
            {
                clearEmsCmd(pStack);//   pStack->usEMSConfCtrl = 0;
            }

            for(int k = 0; k < 10; ++k)
            {
                sendLog(0, QString("=================================================Recv FZ cmd from EMS."));
            }
            usDrvFz = 1;//驱动分闸
            //usDrvFz = waitFzOpt(2, m_drvFzCount, m_drvFzSuccedCount, m_drvFzTime, m_statChangeTime);

            if (m_saveEmsCtrlFzRdCount < 5)
            {
                m_saveEmsCtrlFzRdCount += 1;
                if(2 == emsCtrlHz)
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("远程控制分闸."));
                    else
                        saveLogToBaDb(QString("Remote opening bus switch."));
                }
                else
                {
                    if(isChLang())
                        saveLogToBaDb(kgConvert("远程控制分闸(BMS控制)."));
                    else
                        saveLogToBaDb(QString("Remote opening bus switch(BMS control)."));
                }
            }
        }
        else
            ;
    }

    // step4.下发控制DO1--DO6干结点命令
    bool bSendCmd = sendHzFzCmd(usDrvHz, usDrvFz);
    return bSendCmd;
}

bool DryCtrlThread::sendHzFzCmd(quint16  usDrvHz, quint16  usDrvFz)
{
    bool bSendCmd = false;
    int k;
    int doIndex;

    //发送合闸命令DO1
    //setDoStateHZ(KgGlobalData::ms_hlkgStrategy.hzDoIndex, usDrvHz);
    if (KgGlobalData::ms_hlkgStrategy.hzDoList.size() > 0)
    {
        if (usDrvHz) // 需要合闸*************************
        {

            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.hzDoList);// 先闭合

            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.hzDoList);// 再断开

            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData); // 执行控制分闸命令

            bSendCmd = true;
        }
    }

    //发送分闸命令DO2
    //setDoStateFZ(KgGlobalData::ms_hlkgStrategy.fzDoIndex, usDrvFz);
    if (KgGlobalData::ms_hlkgStrategy.fzDoList.size() > 0)
    {
        if (usDrvFz)// 需要分闸*************************
        {
            /*
            g_DOState |= (1 << KgGlobalData::ms_hlkgStrategy.fzDoIndex);
            setDevAllDoState();

            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            this->msleep(delayTime);//延时300ms
            g_DOState &= ~(1 << KgGlobalData::ms_hlkgStrategy.fzDoIndex);
            setDevAllDoState();
            */
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.fzDoList);// 先闭合

            /*if(1 == m_fireAlarm || 1 == m_waterAlarm || 1 == m_combusGasAlarm) // 发生了消防告警
            {
                if(m_xfTkMotionCount < 3)
                {
                    m_xfTkMotionCount += 1;
                }
                openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);// 先闭合
                if(0 == m_xfTkMotionLogCount)
                {
                    m_xfTkMotionLogCount = 1;
                    doIndex = KgGlobalData::ms_hlkgStrategy.xfTkDoList.at(0);
                    if(isChLang())
                       saveLogToBaDb(kgConvert("消防告警分励脱扣(DO%1).").arg(doIndex+1));
                    else
                       saveLogToBaDb(kgConvert("Fire alarm, opening switch(DO%1).").arg(doIndex+1));
                }
            }

            bool isVolDownProt = hasVolDownPort();
            if(isVolDownProt) // 发生了低电压保护
            {
                if(m_volDownProtTkCount < 3)
                {
                    m_volDownProtTkCount += 1;
                }
                openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);// 先闭合
                if(KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size() > 0 && 0 == m_volDownProtTkLogCount)// modifed 2022-11-17
                {
                    m_volDownProtTkLogCount = 1;
                    doIndex = KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.at(0);
                    if(isChLang())
                       saveLogToBaDb(kgConvert("低电压保护分励脱扣(DO%1).").arg(doIndex+1));
                    else
                       saveLogToBaDb(kgConvert("Vol down protect, opening switch(DO%1).").arg(doIndex+1));
                }
            }*/

            int delayTime = KgGlobalData::ms_tkDelayTime * 1000; /////////////////////////////////////////
            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,delayTime);

            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.fzDoList);// 再断开

            /*if(1 == m_fireAlarm || 1 == m_waterAlarm || 1 == m_combusGasAlarm) // 发生了消防告警
            {
                closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);// 再断开
            }

            if(isVolDownProt)   // 发生了低电压保护
            {
                closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);// 再断开
            }*/

            m_pIOReader->AddSetCmd(0,KgGlobalData::ms_dryData.IOCtrl,0);
            m_pIOReader->DealwithSetDoCmd(0,KgGlobalData::ms_dryData); // 执行控制合闸命令

            msleep(300); // 否则分闸干节点两次控制，中间会断开时间太短 // added 2022-11-17

            bSendCmd = true;
        }
    }

    return bSendCmd;
}

void DryCtrlThread::dealwithConnFailed(int runCount)
{
    // added 2021-3-23
    int connAlarmCount = KgGlobalData::ms_connTimeoutCount;
    if (runCount <  30)     // 程序刚启动时，只需要1次通信故障，就通知BA急停
    {
        connAlarmCount = 1;
    }
    /*else if (30 == runCount)// 启动完毕
    {
        // 原来为通迅故障控制BA停机，则需要继续维持,直到通信正常
        if (g_connFailedCount >= 1 && g_connFailedCount < KgGlobalData::ms_connTimeoutCount)
        {
            g_connFailedCount = KgGlobalData::ms_connTimeoutCount;
            printf("****************************\n");
        }
    }*/
    else
        ;
    //added end
    bool bHasEmerStopStrategy = false;

#ifdef	HAS_EMER_STOP_STRATEGY  // added 2021-3-13
    if (200 == KgGlobalData::ms_pStack->usEmerStopStrategy)
    {
        bHasEmerStopStrategy = true;
    }
#else
    if (999 == KgGlobalData::ms_pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4     紧急停机
    {
        bHasEmerStopStrategy = true;
    }
#endif	

    if (KgGlobalData::ms_dryData.failedCount >= connAlarmCount) // 通迅故障
    {
        KgGlobalData::ms_pStack->aExIOModuConnFault = 1;  // added 2022-5-22
        if (0 == m_usConnFailed || 99 == m_usConnFailed) // have not saved connect errer rd
        {
            m_usConnFailed = 1;
            if(isChLang())
            {

                /*if (bHasEmerStopStrategy && KgGlobalData::ms_emgStopStrategy.diList.size() > 0) // 有采集急停信号
               {
                   saveLogToBaDb(kgConvert("串口继电器通信故障-急停."));
               }
               else
               {
                   saveLogToBaDb(kgConvert("串口继电器通信故障."));
               }
               */
                saveLogToBaDb(kgConvert("串口继电器通信故障."));
            }
            else
            {
                /*if (bHasEmerStopStrategy && KgGlobalData::ms_emgStopStrategy.diList.size() > 0) // 有采集急停信号
                {
                    saveLogToBaDb("Connect to IO module Failed, Emergency Stop.");
                }
                else
                {
                    saveLogToBaDb("Connect to IO module Failed.");
                }
                */
                saveLogToBaDb("Connect to IO module Failed.");
            }

        }
    }
    else if (0 == KgGlobalData::ms_dryData.failedCount)// 通迅正常
    {
        KgGlobalData::ms_pStack->aExIOModuConnFault = 0;
        if (1 == m_usConnFailed || 99 == m_usConnFailed) // have not saved connect OK rd
        {
            m_usConnFailed = 0;

            if(isChLang())
            {

                saveLogToBaDb("串口继电器通信恢复.");
            }
            else
            {
                saveLogToBaDb("Reconnect to IO module OK.");
            }
        }
    }
    else
        ;

    //if (usConnFailed || hasEmertStopAlarm()) // 通迅故障也作为急停处理 道威7.5MWh
    //if (hasEmertStopAlarm())
    //if (m_usConnFailed || hasEmertStopAlarm() || m_fuseAlarm > 0)
    if (hasEmertStopAlarm() || m_fuseAlarm > 0)
    {
        SetEmergeStopAlarm(1);
    }
    else
    {
        SetEmergeStopAlarm(0);
    }

    sendLog(0, QString("runCount:%1, readDiCount:%2, failedCount:%3, connAlarmCount:%4, m_usConnFailed:%5")
            .arg(runCount).arg(KgGlobalData::ms_dryData.readDiCount).arg(KgGlobalData::ms_dryData.failedCount).arg(connAlarmCount).arg(m_usConnFailed));
    if (m_usConnFailed)
    {
        sendLog(0, "******Connect IO dev Failed");
    }
}


quint16 oldFireAlarm = 0;
quint16 oldThunderAlarm = 0;
quint16 oldEmergStopAlarm = 0;
int printCount = 0;
#define PINTT_COUNT 300
void DryCtrlThread::printRealState(quint16 usHasProt, quint16 usEmergStopAlarm)
{
    if(printCount < PINTT_COUNT)
    {
        printCount += 1;

        quint16 lcConnFault = m_pStack->usStackTemp[0];// 通讯故障
        quint16 lcDevFault =  m_pStack->usStackTemp[3];// 故障状态

        if(0)
        {
            printf("[ ****** StackState:%d, HasProt:%d, XfWarmMsg:%d, FireAlarm:%d, FireFaultAlarm:%d, FireSprayAlarm:%d]\n",
                   m_stackState, usHasProt, m_xfWarmMsg, m_fireAlarm, m_fireFaultAlarm, m_fireSprayAlarm);
            printf("[ ****** WaterAlarm:%d-%d(aEnvWaterAlarm[0]:%d), ThunderAlarm:%d, EmergStopAlarm:%d, FuseAlarm:%d, CombusGasAlarm:%d]\n",
                   m_waterAlarm, m_waterAlarmSec, (int)m_pStack->aEnvWaterAlarm[0], m_thunderAlarm, m_emergStopAlarm, m_fuseAlarm, m_combusGasAlarm);
            printf("[ ****** DIState:%d, DOState:%d, ConfSwitchState:%d, BmsLocalState:%d, BmsRemoteState:%d, UpsAlarm:%d, DoorAlarm:%d, ElecPowerOffAlarm:%d]\n",
                   KgGlobalData::ms_dryData.DIVal, KgGlobalData::ms_dryData.IOCtrl, getConfSwitchState(), m_bmsLocalState,
                   m_upsAlarm, m_doorAlarm, m_elecPowerOffAlarm);
            printf("[ ****** LcConnFault:%d, lcDevFault:%d]\n", lcConnFault, lcDevFault);
        }
        else
        {
            QString strLog;
            // modified 2024-12-11
            strLog = QString("aEnvTemp[0]to[7]:%1-%2-%3-%4-%5-%6-%7-%8,aEnvTemp[32]to[39]:%9-%10-%11-%12-%13-%14-%15-%16")
                    .arg((int)m_pStack->aEnvTemp[0]).arg((int)m_pStack->aEnvTemp[1]).arg((int)m_pStack->aEnvTemp[2])
                    .arg((int)m_pStack->aEnvTemp[3]).arg((int)m_pStack->aEnvTemp[4]).arg((int)m_pStack->aEnvTemp[5])
                    .arg((int)m_pStack->aEnvTemp[6]).arg((int)m_pStack->aEnvTemp[7])
                    .arg((int)m_pStack->aEnvTemp[32]).arg((int)m_pStack->aEnvTemp[33]).arg((int)m_pStack->aEnvTemp[34])
                    .arg((int)m_pStack->aEnvTemp[35]).arg((int)m_pStack->aEnvTemp[36]).arg((int)m_pStack->aEnvTemp[37])
                    .arg((int)m_pStack->aEnvTemp[38]).arg((int)m_pStack->aEnvTemp[39]);
            writeKgLogfile(strLog, true);

            strLog = QString("防雷告警:%1,熔断告警:%2,可燃气体:%3,UPS告警:%4,门禁告警:%5-%6,市电断电:%7,液冷机通迅故障:%8-%9")
                    .arg(m_thunderAlarm).arg(m_fuseAlarm).arg(m_combusGasAlarm).arg(m_upsAlarm)
                    .arg(m_doorAlarm).arg(m_doorAlarmSec).arg(m_elecPowerOffAlarm)
                    .arg(lcConnFault).arg(lcDevFault);
            writeKgLogfile(strLog, true);

            strLog = QString("堆状态:%1-%2,急停:%3-%4,消防:%5-%6-%7-%8,水浸:%9-%10(%11),汇流开关:%12,就地/远方:%13-%14,DIDOState:%15-%16.")
                    .arg(m_stackState).arg(usHasProt).arg((int)m_emergStopAlarm).arg((int)m_emergStopAlarmSec)
                    .arg(m_xfWarmMsg).arg(m_fireAlarm).arg(m_fireFaultAlarm).arg(m_fireSprayAlarm)
                    .arg(m_waterAlarm).arg(m_waterAlarmSec).arg((int)m_pStack->aEnvWaterAlarm[0]).arg(getConfSwitchState())
                    .arg(m_bmsLocalState).arg(m_bmsRemoteState).arg(KgGlobalData::ms_dryData.DIVal).arg(KgGlobalData::ms_dryData.IOCtrl);
            writeKgLogfile(strLog, true);
        }
    }
}

void DryCtrlThread::setSomeDOState()
{
    // 初始化状态变量
    quint16 usHasProt = 0, usHasAlarm = 0, usChargeFull = 0;
    quint16 usDischargeEmpty = 0, usProhibitChgDchg = 0, usEmergStopAlarm = 0;

    // 获取BAMS运行状态
    sendLog(0, "Waiting stack state changed...");
    waitForStateChange(usEmergStopAlarm);

    // 解析堆栈状态
    parseStackState(m_stackState, usHasProt, usHasAlarm, usChargeFull, usDischargeEmpty, usProhibitChgDchg);

#ifdef LSZH_PRJ
    lszhParseDLQState(usHasProt, usEmergStopAlarm);
#endif

#ifdef ND_VER_PROGRAM // 南都版本
    if(2 != KgGlobalData::ms_pStack->usConnState) // 2-成功
    {
        usHasProt = 1;
    }
#endif

    // 处理资源中断告警
    if(hasResBreakAlarm() > 0)
    {
        usHasProt = 1;
        m_pStack->aGasAlarm = 1; // 通知xnprocsrv跳机
    }
    else
    {
        m_pStack->aGasAlarm = 0;
    }

    printRealState(usHasProt, usEmergStopAlarm);

#ifdef LYGWK_PRJ
    usHasAlarm = isBankAlarm(); // 连云港威控项目-有实时告警时才算有告警
#endif

    // 更新旧状态
    updateOldStates(usEmergStopAlarm);

    // 记录状态日志
    logCurrentState(usHasProt, usHasAlarm, usChargeFull, usDischargeEmpty);

    // 准备设置DO状态
    quint16 olDoState = KgGlobalData::ms_dryData.IOCtrl;
    quint16 newIOCtrl = olDoState;

    // 设置各类干结点状态
    setFaultDryContacts(newIOCtrl, usHasProt, usEmergStopAlarm);
    setAllBankFaultContacts(newIOCtrl);
    setRunningLightContacts(newIOCtrl, usHasProt, usEmergStopAlarm);
    setConstantLightContacts(newIOCtrl);
    setAlarmContacts(newIOCtrl, usHasAlarm);
    setChargingProhibitContacts(newIOCtrl, usHasProt, usChargeFull, usProhibitChgDchg, usEmergStopAlarm);
    setDischargingProhibitContacts(newIOCtrl, usHasProt, usDischargeEmpty, usProhibitChgDchg, usEmergStopAlarm);
    setChargingDriveContacts(newIOCtrl, usHasProt, usChargeFull, usProhibitChgDchg, usEmergStopAlarm);
    setDischargingDriveContacts(newIOCtrl, usHasProt, usDischargeEmpty, usProhibitChgDchg, usEmergStopAlarm);
    setRegisterControlContacts(newIOCtrl);
    setFireActionContacts(newIOCtrl);
    setFireSprayActionContacts(newIOCtrl);
    setLightningActionContacts(newIOCtrl);
    setBmsEmsCommFaultContacts(newIOCtrl);
    setFanDriveContacts(newIOCtrl, usEmergStopAlarm);
    setTemperatureDriveContacts(newIOCtrl);
    setBcmuAddressAllocationContacts(newIOCtrl);
    setSmokeAndHeatDriveContacts(newIOCtrl);

    // 重置默认断开的干结点
    resetDefaultOpenContacts(newIOCtrl);

    // 仅当DO状态变化时才下发指令
    if(olDoState != newIOCtrl)
    {
        m_pIOReader->AddSetCmd(0, newIOCtrl, 0);
    }

    // 执行设置命令
    m_pIOReader->DealwithSetDoCmd(0, KgGlobalData::ms_dryData);
}

// 等待状态变化
void DryCtrlThread::waitForStateChange(quint16 &usEmergStopAlarm)
{
    for(int k = 0; k < 25; ++k) // 等待0.5秒
    {
        this->msleep(20);

        // 检查堆栈状态变化
        if (m_stackState != KgGlobalData::ms_pStack->usStackState)
        {
            m_stackState = KgGlobalData::ms_pStack->usStackState;
            m_statChangeTime = QDateTime::currentDateTime();
            resetDriveCounters();
            sendLog(0, "StackState has Changed.");
            break;
        }

        // 检查火灾告警变化
        if (oldFireAlarm != m_fireAlarm)
        {
            sendLog(0, "FireAlarm state has Changed.");
            break;
        }

        // 检查雷电告警变化
        if (oldThunderAlarm != m_thunderAlarm)
        {
            sendLog(0, "ThunderAlarm state has Changed.");
            break;
        }

        // 检查紧急停机状态
        usEmergStopAlarm = hasEmertStopAlarm() ? 1 : 0;
        if (oldEmergStopAlarm != usEmergStopAlarm)
        {
            sendLog(0, "EmergStopAlarm state has Changed.");
            break;
        }
    }
}

// 重置驱动计数器
void DryCtrlThread::resetDriveCounters()
{
    m_drvFzCount = 0;
    m_drvHzCount = 0;
    m_drvFzSuccedCount = 0;
    m_drvHzSuccedCount = 0;
    m_saveEmsCtrlHzRdCount = 0;
    m_saveEmsCtrlFzRdCount = 0;
    m_saveRejectEmsHzRdCount = 0;
}

// 更新旧状态
void DryCtrlThread::updateOldStates(quint16 usEmergStopAlarm)
{
    oldFireAlarm = m_fireAlarm;
    oldThunderAlarm = m_thunderAlarm;
    oldEmergStopAlarm = usEmergStopAlarm;
}

// 记录当前状态日志
void DryCtrlThread::logCurrentState(quint16 usHasProt, quint16 usHasAlarm, quint16 usChargeFull, quint16 usDischargeEmpty)
{
    QChar fillChar = '0';
    QString strState = QString("%1").arg(m_stackState, 4, 16, fillChar).toUpper();
    QString strHint = QString("State:0X%1, HasProt:%2, HasAlarm:%3, ChgFull:%4, DischgEmpty:%5.")
            .arg(strState).arg(usHasProt).arg(usHasAlarm).arg(usChargeFull).arg(usDischargeEmpty);
    sendLog(0, strHint);
}

// 设置故障干结点
void DryCtrlThread::setFaultDryContacts(quint16 &newIOCtrl, quint16 usHasProt, quint16 usEmergStopAlarm)
{
    for(int k = 0; k < KgGlobalData::ms_gzCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_gzCtrlList[k];
        quint16 usAllProt = usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm |
                           m_waterAlarm | m_thunderAlarm | usEmergStopAlarm | m_combusGasAlarm |
                           m_bmsSmokeAlarm | m_bmsHeatAlarm;
        setDoState(newIOCtrl, stg.doIndex, usAllProt);
    }
}

// 设置所有簇故障干结点
void DryCtrlThread::setAllBankFaultContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_gzHzCtrlList.size(); ++k)
    {
        quint16 usAllBankFault = isAllBankFault();
        DOStrategy stg = KgGlobalData::ms_gzHzCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, usAllBankFault ? 0 : 1);
    }
}

// 设置运行灯干结点
void DryCtrlThread::setRunningLightContacts(quint16 &newIOCtrl, quint16 usHasProt, quint16 usEmergStopAlarm)
{
    for(int k = 0; k < KgGlobalData::ms_runCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_runCtrlList[k];
        quint16 hasFault = usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm |
                          m_waterAlarm | m_thunderAlarm | usEmergStopAlarm | m_fuseAlarm |
                          hasCombusGasAlarm() | m_bmsSmokeAlarm | m_bmsHeatAlarm;
        setDoState(newIOCtrl, stg.doIndex, hasFault ? 0 : 1);
    }
}

// 设置常亮灯干结点
void DryCtrlThread::setConstantLightContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_allLightCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_allLightCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, 1); // 常亮灯
    }
}

// 设置告警干结点
void DryCtrlThread::setAlarmContacts(quint16 &newIOCtrl, quint16 usHasAlarm)
{
    for(int k = 0; k < KgGlobalData::ms_alarmCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_alarmCtrlList[k];
        if(0 == k && 1 == KgGlobalData::ms_saveHlkgLog)
        {
            logAlarmStateChange(stg.doIndex, usHasAlarm);
        }
        setDoState(newIOCtrl, stg.doIndex, usHasAlarm);
    }
}

// 记录告警状态变化
void DryCtrlThread::logAlarmStateChange(int doIndex, quint16 usHasAlarm)
{
    if(usHasAlarm && !m_usOldHasAlarm)
    {
        if(isChLang())
            saveLogToBaDb(kgConvert("打开告警干结点") + QString("(DO%1).").arg(doIndex + 1));
        else
            saveLogToBaDb(QString("Open alarm dry contact(DO%1).").arg(doIndex + 1));
    }

    if(!usHasAlarm && m_usOldHasAlarm)
    {
        if(isChLang())
            saveLogToBaDb(kgConvert("关闭告警干结点") + QString("(DO%1).").arg(doIndex + 1));
        else
            saveLogToBaDb(QString("Close alarm dry contact(DO%1).").arg(doIndex + 1));
    }

    m_usOldHasAlarm = usHasAlarm;
}

// 设置禁充干结点
void DryCtrlThread::setChargingProhibitContacts(quint16 &newIOCtrl, quint16 usHasProt,
                                               quint16 usChargeFull, quint16 usProhibitChgDchg,
                                               quint16 usEmergStopAlarm)
{
    int hasOtherAlam = 0;
#ifdef YW0357_PRJ
    hasOtherAlam = 0; // isBoxVolTempDiffAlarm();
#endif

    for(int k = 0; k < KgGlobalData::ms_phbChgList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_phbChgList[k];
        quint16 prohibitCharge = hasOtherAlam | usHasProt | m_fireAlarm | m_fireFaultAlarm |
                                m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm |
                                usEmergStopAlarm | m_fuseAlarm | usChargeFull |
                                usProhibitChgDchg | hasCombusGasAlarm();
        setDoState(newIOCtrl, stg.doIndex, prohibitCharge);
    }
}

// 设置禁放干结点
void DryCtrlThread::setDischargingProhibitContacts(quint16 &newIOCtrl, quint16 usHasProt,
                                                  quint16 usDischargeEmpty, quint16 usProhibitChgDchg,
                                                  quint16 usEmergStopAlarm)
{
    int hasOtherAlam = 0;
#ifdef YW0357_PRJ
    hasOtherAlam = 0; // isBoxVolTempDiffAlarm();
#endif

    for(int k = 0; k < KgGlobalData::ms_phbDischgList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_phbDischgList[k];
        quint16 prohibitDischarge = hasOtherAlam | usHasProt | m_fireAlarm | m_fireFaultAlarm |
                                  m_fireSprayAlarm | m_waterAlarm | m_thunderAlarm |
                                  usEmergStopAlarm | m_fuseAlarm | usDischargeEmpty |
                                  usProhibitChgDchg | hasCombusGasAlarm();
        setDoState(newIOCtrl, stg.doIndex, prohibitDischarge);
    }
}

// 设置充电驱动干结点
void DryCtrlThread::setChargingDriveContacts(quint16 &newIOCtrl, quint16 usHasProt,
                                            quint16 usChargeFull, quint16 usProhibitChgDchg,
                                            quint16 usEmergStopAlarm)
{
    for(int k = 0; k < KgGlobalData::ms_chgDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_chgDriveList[k];
        quint16 hasFault = usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm |
                          m_waterAlarm | m_thunderAlarm | usEmergStopAlarm | m_fuseAlarm |
                          usChargeFull | usProhibitChgDchg | hasCombusGasAlarm();
        setDoState(newIOCtrl, stg.doIndex, hasFault ? 0 : 1);
    }
}

// 设置放电驱动干结点
void DryCtrlThread::setDischargingDriveContacts(quint16 &newIOCtrl, quint16 usHasProt,
                                              quint16 usDischargeEmpty, quint16 usProhibitChgDchg,
                                              quint16 usEmergStopAlarm)
{
    for(int k = 0; k < KgGlobalData::ms_dchgDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_dchgDriveList[k];
        quint16 hasFault = usHasProt | m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm |
                          m_waterAlarm | m_thunderAlarm | usEmergStopAlarm | m_fuseAlarm |
                          usDischargeEmpty | usProhibitChgDchg | hasCombusGasAlarm();
        setDoState(newIOCtrl, stg.doIndex, hasFault ? 0 : 1);
    }
}

// 设置寄存器控制干结点
void DryCtrlThread::setRegisterControlContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_keepRegCtrlDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_keepRegCtrlDriveList[k];
        if(KgGlobalData::ms_keepRegCtrlPos > 49)
            KgGlobalData::ms_keepRegCtrlPos = 49;

        int ctrlVal = KgGlobalData::ms_pStack->usStackHoldTemp[KgGlobalData::ms_keepRegCtrlPos];
        setDoState(newIOCtrl, stg.doIndex, ctrlVal > 0 ? 1 : 0);
    }
}

// 设置消防动作干结点
void DryCtrlThread::setFireActionContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_xfStrategy.xfCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_xfStrategy.xfCtrlList[k];
        quint16 fireAction = m_fireAlarm | m_fireFaultAlarm | m_fireSprayAlarm |
                            m_waterAlarm | m_thunderAlarm | hasCombusGasAlarm();
        setDoState(newIOCtrl, stg.doIndex, fireAction);
    }
}

// 设置消防喷洒动作干结点
void DryCtrlThread::setFireSprayActionContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_xfSprayStrategy.xfCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_xfSprayStrategy.xfCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, m_fireSprayAlarm);
    }
}

// 设置防雷动作干结点
void DryCtrlThread::setLightningActionContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_tdStrategy.xfCtrlList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_tdStrategy.xfCtrlList[k];
        setDoState(newIOCtrl, stg.doIndex, m_thunderAlarm);
    }
}

// 设置BMS-EMS通信故障干结点
void DryCtrlThread::setBmsEmsCommFaultContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_bmsEmsCommFaultList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_bmsEmsCommFaultList[k];
        quint16 usCommFault = 0;
#ifdef ND_VER_PROGRAM // 南都版本
        // Bit3: EMS通信故障报警
        if ((KgGlobalData::ms_pStack->usStackTotAlarm & (1 << 3)) > 0)
        {
            usCommFault = 1;
        }
#endif
        setDoState(newIOCtrl, stg.doIndex, usCommFault);
    }
}

// 设置风扇驱动干结点
void DryCtrlThread::setFanDriveContacts(quint16 &newIOCtrl, quint16 usEmergStopAlarm)
{
    for(int k = 0; k < KgGlobalData::ms_fanDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_fanDriveList[k];
        float fStackCur = fabs(KgGlobalData::ms_pStack->fStackCur);

        // 火灾、喷淋、紧急停机或电流过小时关闭风扇
        if (m_fireAlarm || m_fireSprayAlarm || usEmergStopAlarm || fStackCur < KgGlobalData::ms_minChgDchgCur)
        {
            if(0 == m_oldCtrlFanState)
            {
                setDoState(newIOCtrl, stg.doIndex, 0); // 关闭风扇
            }
            else // 有驱动过风扇, 延时关闭
            {
                handleFanDelayedShutdown(newIOCtrl, stg.doIndex);
            }
        }
        else
        {
            m_oldCtrlFanState = 1; // 驱动风扇标记
            m_closeFanReqCount = 0;
            setDoState(newIOCtrl, stg.doIndex, 1); // 打开风扇
        }
    }
}

// 处理风扇延时关闭
void DryCtrlThread::handleFanDelayedShutdown(quint16 &newIOCtrl, int doIndex)
{
    if(0 == m_closeFanReqCount)
    {
        m_closeReqStartTime = QDateTime::currentDateTime();
        m_closeFanReqCount += 1;
    }
    else
    {
        QDateTime nowTime = QDateTime::currentDateTime();
        int elapseSec = m_closeReqStartTime.secsTo(nowTime);
        if(elapseSec >= KgGlobalData::ms_closeFanDelayTime)
        {
            m_oldCtrlFanState = 0; // 驱动风扇标记清0
            setDoState(newIOCtrl, doIndex, 0);
        }
    }
}

// 设置温度驱动干结点
void DryCtrlThread::setTemperatureDriveContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_tempDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_tempDriveList[k];
        bool overTemp = KgGlobalData::ms_pStack->fSglMaxTempInStack > KgGlobalData::ms_openFanTemp;
        setDoState(newIOCtrl, stg.doIndex, overTemp ? 1 : 0);
    }
}

// 设置BCMU地址分配干结点
void DryCtrlThread::setBcmuAddressAllocationContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_allocAddressList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_allocAddressList[k];
        CBattBank *pFirstBank = KgGlobalData::ms_pRTDB->getBank(0);

        if(this->m_bcmuAddrAllocReq == 1)
        {
            netDebug->kgWrite(QString("DO 闭合%1").arg(this->m_bcmuAddrAllocReq));
            setDoState(newIOCtrl, stg.doIndex, 1);
            msleep(1000);

            if (pFirstBank && !m_addressAllocCommandSent)
            {
                pFirstBank->usBankHoldTemp[49] = 1; // 1-地址自动分配命令
                printf("\n   pFirstBank->usBankHoldTemp[49]  =%d  \n", pFirstBank->usBankHoldTemp[49]);
                m_addressAllocCommandSent = true; // 标记已经下发过命令

                netDebug->kgWrite(QString("进入BCMU地址手动分配流程%1-----------------------").arg(this->m_doCloseCounter));
                setAddressAllocRequestToZero();
            }
        }
        else
        {
            setDoState(newIOCtrl, stg.doIndex, 0);
            netDebug->kgWrite(QString("DO 长开").arg(this->m_bcmuAddrAllocReq));
            this->m_doCloseCounter += 1;
            netDebug->kgWrite(QString("usBankHoldTemp[49]=%1").arg(pFirstBank->usBankHoldTemp[49]));
        }
    }
}

// 设置烟感和温感驱动干结点
void DryCtrlThread::setSmokeAndHeatDriveContacts(quint16 &newIOCtrl)
{
    for(int k = 0; k < KgGlobalData::ms_smokeAndHeatDriveList.size(); ++k)
    {
        DOStrategy stg = KgGlobalData::ms_smokeAndHeatDriveList[k];
        bool bothAlarms = m_bmsSmokeAlarm > 0 && m_bmsHeatAlarm > 0;
        setDoState(newIOCtrl, stg.doIndex, bothAlarms ? 1 : 0);
    }
}

// 重置默认断开的干结点
void DryCtrlThread::resetDefaultOpenContacts(quint16 &newIOCtrl)
{
    // 重置合闸口（默认断开）
    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.hzDoList.size(); ++k)
    {
        int doIndex = KgGlobalData::ms_hlkgStrategy.hzDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 重置分闸口（默认断开）
    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.fzDoList.size(); ++k)
    {
        int doIndex = KgGlobalData::ms_hlkgStrategy.fzDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 重置消防脱扣分闸口（默认断开）
    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.xfTkDoList.size(); ++k)
    {
        int doIndex = KgGlobalData::ms_hlkgStrategy.xfTkDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 重置消防喷洒脱扣分闸口（默认断开）
    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size(); ++k)
    {
        int doIndex = KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }

    // 重置低电压保护分励脱扣（默认断开）
    for (int k = 0; k < KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size(); ++k)
    {
        int doIndex = KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList[k];
        newIOCtrl &= ~(1 << doIndex);
    }
}

void DryCtrlThread::dealwithBcmuAddressAllocation()
{
    // 检查一键分配配置，如果为1则设置地址分配请求
    if (readIsOneClickAllocate() && readBcmuAddressMode() == 1)
    {
        checkBcmuAddressAllocManuTrigger();
    }
    if(readBcmuAddressMode() == 0)
    {
        checkBcmuAddressAllocAutoTrigger();   // 自动分配
    }
}
#include "QNetDebug.h"
// 读取地址分配模式
int DryCtrlThread::readBcmuAddressMode()
{
    QSettings settings("../ini/xnview_zh.ini", QSettings::IniFormat);
    settings.setIniCodec("UTF-8");
    return settings.value("BCMU/AllocateAddressMode").toInt();
}

// 读取一键分配配置
bool DryCtrlThread::readIsOneClickAllocate()
{
    QSettings settings("../ini/xnview_zh.ini", QSettings::IniFormat);
    settings.setIniCodec("UTF-8");
    return settings.value("BCMU/IsOneClickAllocate").toBool();
}

// 写入地址分配模式
void DryCtrlThread::writeBcmuAddressMode(int mode)
{
    QSettings settings("../ini/xnview_zh.ini", QSettings::IniFormat);
    settings.setIniCodec("UTF-8");
    settings.setValue("BCMU/AllocateAddressMode", mode);
    settings.sync();
}

// 写入一键分配配置
void DryCtrlThread::writeIsOneClickAllocate(bool enable)
{

    QSettings settings("../ini/xnview_zh.ini", QSettings::IniFormat);
    settings.setIniCodec("UTF-8");
    settings.setValue("BCMU/IsOneClickAllocate", enable ? 1 : 0);
    settings.sync();
}
// 检查是否有BCMU地址分配的手动触发条件
void DryCtrlThread::checkBcmuAddressAllocManuTrigger()   //手动分配
{
    // 获取堆栈对象，检查是否为空
    CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
    if (!pStack) {
         netDebug->kgWrite(QString("手动分配错误：无法获取堆栈对象"));
        return;
    }

    // 设置地址分配请求标志
    this->m_bcmuAddrAllocReq = 1;
    this->m_addressAllocCommandSent = false;
    // 记录日志
    netDebug->kgWrite(QString("进入BCMU地址手动分配流程"));

    // 设置地址分配命令
    CBattBank *pFirstBank = KgGlobalData::ms_pRTDB->getBank(0);
    if (pFirstBank)
    {
        netDebug->kgWrite(QString("已设置usBankHoldTemp[49]=%1，触发地址分配").arg(pFirstBank->usBankHoldTemp[49]));
        
        // 使用定时器在6秒后自动复位，避免阻塞线程
        // 注意：将setAddressAllocRequestToZero移到这里，确保在设置标志后才清除请求
        setAddressAllocRequestToZero();
    } else {
        netDebug->kgWrite(QString("手动分配错误：无法获取第一个簇对象"));
    }
    // 重置一键分配配置，防止重复触发
    this->writeIsOneClickAllocate(false);
}
//创建一个定时器  通过配置文件读秒后自动设置  false
void DryCtrlThread::setAddressAllocRequestToZero() {
    // 从配置文件读取超时时间，默认为6000毫秒
    QSettings settings("../ini/xnview_zh.ini", QSettings::IniFormat);
    settings.setIniCodec("UTF-8");
    int timeoutMs = settings.value("BCMU/AllocTimeOut", 6000).toInt();
    
    QTimer::singleShot(timeoutMs, this, [this]() {
        m_bcmuAddrAllocReq = false;
        CBattBank *pFirstBank = KgGlobalData::ms_pRTDB->getBank(0);
        pFirstBank->usBankHoldTemp[49] = 0;  // 1- 地址自动分配命令
    });
}
void DryCtrlThread::checkBcmuAddressAllocAutoTrigger()   //自动分配
{
    // 获取堆栈对象，检查是否为空
    CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
    if (!pStack)
    {
        netDebug->kgWrite(QString("自动分配错误：无法获取堆栈对象"));
        m_bcmuAddrAllocReq = false;
        return;
    }

    // 检查所有簇是否有BCMU连接故障
    bool hasBcmuConnFault = false;
    bool hasStatusChanged = false;
    netDebug->kgWrite(QString("BCMU地址自动分配检测：已安装簇数量 = %1").arg(pStack->usInstallBankNum));

    for (int k = 0; k < pStack->usInstallBankNum; ++k)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);
        if (!pBank) continue; // 跳过空对象

        // 检测状态变化：从正常变为故障
        if (pBank->aBCMUConnFault == 1 && m_lastBcmuConnFault[k] == 0)
        {
            hasBcmuConnFault = true;
            hasStatusChanged = true;
            netDebug->kgWrite(QString("检测到%1#簇BCMU连接故障，触发地址自动分配").arg(k+1));
        }

        // 更新状态记录
        m_lastBcmuConnFault[k] = pBank->aBCMUConnFault;
    }

    // 只在状态变化时触发分配
    if (hasBcmuConnFault && hasStatusChanged)
    {
        netDebug->kgWrite(QString("发送BCMU地址自动分配指令"));
        CBattBank *pFirstBank = KgGlobalData::ms_pRTDB->getBank(0);
        if (pFirstBank) {
            //pFirstBank->usBankHoldTemp[49] = 1;  // 1- 地址自动分配命令
            this->m_bcmuAddrAllocReq = 1;

            // 使用定时器在6秒后自动复位，避免阻塞线程
            setAddressAllocRequestToZero();
        } else {
            netDebug->kgWrite(QString("自动分配错误：无法获取第一个簇对象"));
        }
    }
    else if (!hasBcmuConnFault)
    {
        netDebug->kgWrite(QString("BCMU连接状态正常"));
        this->m_bcmuAddrAllocReq = 0;
    }
}
int g_xfSprayCount = 0;

void DryCtrlThread::controlOtherFz()
{
    // 处理消防告警触发的脱扣
    handleFireAlarm();

    // 处理消防喷洒告警触发的脱扣
    handleFireSprayAlarm();

    // 处理低电压保护触发的脱扣
    handleVolDownProtection();
}

// 处理消防告警触发的脱扣
void DryCtrlThread::handleFireAlarm()
{
    // 判断是否发生消防告警、消防喷洒告警、急停告警或水浸告警
    bool hasAlarm = (1 == m_fireAlarm || 1 == m_fireSprayAlarm ||
                    (hasEmertStopAlarm() && isEmgTkEnabled()) ||
                    (hasWaterAlarm() && isWaterTkEnabled()));

    if(hasAlarm)
    {
        // 有消防脱扣干节点且(脱扣次数小于3或有闭合的确认开关)
        if(KgGlobalData::ms_hlkgStrategy.xfTkDoList.size() > 0 &&
          (m_xfTkMotionCount < 3 || getClosedConfSwitchCount() > 0))
        {
            ++m_xfTkMotionCount;

            // 获取DO名称
            QString strDoName = getDOName(KgGlobalData::ms_hlkgStrategy.xfTkDoList);

            // 打开DO
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);

            // 设置延时
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0, KgGlobalData::ms_dryData.IOCtrl, delayTime);

            // 记录不同类型告警的日志
            logAlarmEvents(strDoName);

            // 关闭DO
            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfTkDoList);

            // 执行命令并等待
            executeCommandAndWait();
        }
    }
    else
    {
        // 重置计数器
        resetFireAlarmCounters();
    }
}

// 处理消防喷洒告警触发的脱扣
void DryCtrlThread::handleFireSprayAlarm()
{
    // 判断是否发生喷洒告警、烟感告警、温感告警、急停告警或水浸告警
    bool hasSprayAlarm = (m_fireSprayAlarm + m_bmsSmokeAlarm + m_bmsHeatAlarm > 0 ||
                         (hasEmertStopAlarm() && isEmgTkEnabled()) ||
                         (hasWaterAlarm() && isWaterTkEnabled()));

    if(hasSprayAlarm)
    {
        // 增加喷洒计数
        if(g_xfSprayCount < 1000)
        {
            g_xfSprayCount += 1;
        }

        // 有消防喷洒脱扣干节点且(脱扣次数小于3或有闭合的确认开关)
        if(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size() > 0 &&
          (m_xfSprayTkMotionCount < 3 || getClosedConfSwitchCount() > 0))
        {
            ++m_xfSprayTkMotionCount;

            // 获取DO名称
            QString strDoName = getDOName(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);

            // 先闭合
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);

            // 设置延时
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0, KgGlobalData::ms_dryData.IOCtrl, delayTime);

            // 记录不同类型告警的日志
            logSprayAlarmEvents(strDoName);

            // 再断开
            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);

            // 执行命令并等待
            executeCommandAndWait();
        }
    }
    else
    {
        // 重置计数器
        resetSprayAlarmCounters();
    }
}

// 处理低电压保护触发的脱扣
void DryCtrlThread::handleVolDownProtection()
{
    bool isVolDownProt = hasVolDownPort();

    if(isVolDownProt)
    {
        // 有低电压保护脱扣干节点且脱扣次数小于3
        if(KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size() > 0 && m_volDownProtTkCount < 3)
        {
            ++m_volDownProtTkCount;

            // 获取DO名称
            QString strDoName = getDOName(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList);

            // 先闭合
            openDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);

            // 设置延时
            int delayTime = KgGlobalData::ms_tkDelayTime * 1000;
            m_pIOReader->AddSetCmd(0, KgGlobalData::ms_dryData.IOCtrl, delayTime);

            // 记录日志
            if(0 == m_volDownProtTkLogCount)
            {
                m_volDownProtTkLogCount = 1;

                if(isChLang())
                    saveLogToBaDb(kgConvert("低电压保护分励脱扣") + QString("(%1).").arg(strDoName));
                else
                    saveLogToBaDb(QString("Vol down protect, opening switch(%1).").arg(strDoName));
            }

            // 再断开
            closeDos(KgGlobalData::ms_dryData.IOCtrl, KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList);

            // 执行命令并等待
            executeCommandAndWait();
        }
    }
    else
    {
        // 重置计数器
        m_volDownProtTkCount = 0;
        m_volDownProtTkLogCount = 0;
    }
}

// 记录消防告警事件的日志
void DryCtrlThread::logAlarmEvents(const QString &strDoName)
{
    // 记录消防告警日志
    if(1 == m_fireAlarm && 0 == m_xfTkMotionLogCount)
    {
        m_xfTkMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("消防告警,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Fire alarm, shunt trip switch(%1).").arg(strDoName));
    }

    // 记录消防喷洒告警日志
    if(1 == m_fireSprayAlarm && 0 == m_xfSprayTkMotionLogCount)
    {
        m_xfSprayTkMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("消防喷洒,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Fire spray alarm, shunt trip switch(%1).").arg(strDoName));
    }

    // 记录急停告警日志
    if(hasEmertStopAlarm() && isEmgTkEnabled() && 0 == m_emgTkMotionLogCount)
    {
        m_emgTkMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("急停,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Emergency, shunt trip switch(%1).").arg(strDoName));
    }
}

// 记录喷洒告警事件的日志
void DryCtrlThread::logSprayAlarmEvents(const QString &strDoName)
{
    // 记录消防喷洒告警日志
    if(1 == m_fireSprayAlarm && 0 == m_xfSprayTkMotionLogCount)
    {
        m_xfSprayTkMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("消防喷洒,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Fire spray alarm, opening switch(%1).").arg(strDoName));
    }

    // 记录急停告警日志
    if(hasEmertStopAlarm() && isEmgTkEnabled() && 0 == m_emgTkMotionLogCount)
    {
        m_emgTkMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("急停,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Emergency, opening switch(%1).").arg(strDoName));
    }

    // 记录水浸告警日志
    if(hasWaterAlarm() && isWaterTkEnabled() && 0 == m_waterTkMotionLogCount)
    {
        m_waterTkMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("水浸告警,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Water alarm, shunt trip switch(%1).").arg(strDoName));
    }

    // 记录烟感告警日志
    if(m_bmsSmokeAlarm && 0 == m_bmsSmokeMotionLogCount)
    {
        m_bmsSmokeMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("烟感告警,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Smoke alarm, opening switch(%1).").arg(strDoName));
    }

    // 记录温感告警日志
    if(m_bmsHeatAlarm && 0 == m_bmsHeatMotionLogCount)
    {
        m_bmsHeatMotionLogCount = 1;
        if(isChLang())
            saveLogToBaDb(kgConvert("温感告警,分励脱扣") + QString("(%1).").arg(strDoName));
        else
            saveLogToBaDb(QString("Heat alarm, opening switch(%1).").arg(strDoName));
    }
}

// 执行命令并等待
void DryCtrlThread::executeCommandAndWait()
{
    m_pIOReader->AddSetCmd(0, KgGlobalData::ms_dryData.IOCtrl, 0);
    m_pIOReader->DealwithSetDoCmd(0, KgGlobalData::ms_dryData);
    this->msleep(200);
}

// 重置消防告警计数器
void DryCtrlThread::resetFireAlarmCounters()
{
    m_xfTkMotionCount = 0;
    m_xfTkMotionLogCount = 0;
    m_xfSprayTkMotionLogCount = 0;
    m_emgTkMotionLogCount = 0;
}

// 重置喷洒告警计数器
void DryCtrlThread::resetSprayAlarmCounters()
{
    m_xfSprayTkMotionCount = 0;
    m_waterTkMotionLogCount = 0;
    m_xfSprayTkMotionLogCount = 0;
    m_emgTkMotionLogCount = 0;
    m_bmsSmokeMotionLogCount = 0;
    m_bmsHeatMotionLogCount = 0;
    g_xfSprayCount = 0;
}

// 更新DI状态到ini文件
void DryCtrlThread::updateDIStateToIniFile()
{
    // 获取当前DI状态
    return  ;
    quint16 currentDIVal = KgGlobalData::ms_dryData.DIVal;
    bool hasChanged = false;
    
    // 检查每个DI状态是否有变化
    for (int i = 0; i < 16; i++) {
        // 计算当前DI的状态 (0或1)
        quint16 currentDIState = (currentDIVal & (1 << i)) ? 1 : 0;
        quint16 oldDIState = (m_usOldDI[i]) ? 1 : 0;
        
        // 如果状态发生变化
        if (currentDIState != oldDIState) {
            // 更新旧状态记录
            m_usOldDI[i] = currentDIState;
            hasChanged = true;
            
            // 记录日志
            QString strLog = QString("DI%1 state changed from %2 to %3")
                .arg(i+1).arg(oldDIState).arg(currentDIState);
            sendLog(0, strLog);
        }
    }
    
    // 如果有状态变化，则更新ini文件
    if (hasChanged) {
        // 打开ini文件
        QSettings settings("../ini/xnbmsio.ini", QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        
        // 更新DIColl部分的配置
        for (int i = 0; i < 16; i++) {
            QString key = QString("DIColl/DI%1Strategy").arg(i+1);
            settings.setValue(key, m_usOldDI[i]);
        }
        
        // 同步到文件
        settings.sync();
        
        sendLog(0, "Updated DI states to xnbmsio.ini file");
    }
}

//控制DO口是否闭合(打开继电器)
bool DryCtrlThread::setDoState0(quint16 doIndex, quint16 usSetVal)
{
    /*
    操作DO  打开第1个继电器
    发送:FE 05 00 00 FF 00 98 35
    接收:FE 05 00 00 FF 00 98 35
    */
    unsigned short cmd = 0;
    QString strLog;

    if (usSetVal)//需要打开
    {
        strLog = QString("UsSetVal:%1, set DO%2 to open.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        KgGlobalData::ms_dryData.IOCtrl |= (1 << doIndex);
    }
    else
    {
        //strLog = QString("==================usSetVal:%1, set DO%2 to close").arg(usSetVal).arg(doIndex+1);
        strLog = QString("UsSetVal:%1, set DO%2 to close.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        //g_DOState &= ~(1 << doIndex);
        KgGlobalData::ms_dryData.IOCtrl &= ~(1 << doIndex);
    }

    return true;////////////////////////////

}

//控制DO口是否闭合(打开继电器)
bool DryCtrlThread::setDoState(quint16 &IOCtrl, quint16 doIndex, quint16 usSetVal)
{
    unsigned short cmd = 0;
    QString strLog;

    if (usSetVal)//需要打开
    {
        strLog = QString("UsSetVal:%1, set DO%2 to open.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        IOCtrl |= (1 << doIndex);
    }
    else
    {
        strLog = QString("UsSetVal:%1, set DO%2 to close.").arg(usSetVal).arg(doIndex+1);
        sendLog(0, strLog);
        IOCtrl &= ~(1 << doIndex);
    }

    return true;////////////////////////////
}

void DryCtrlThread::readDIValue(quint16 runCount)
{
    int ret = readDevDIState(KgGlobalData::ms_pStack, KgGlobalData::ms_dryData.failedCount);

    // 刚检测到有消防信号，或防雷信号，或急停信号,但还没报警, 再读一次进行确认 // added 2021-3-25
    if ((m_fireAlarmCount > 0 && m_fireAlarmCount < KgGlobalData::ms_xfStrategy.confirmedCount) ||
            (m_thunderCount > 0 && m_thunderCount < KgGlobalData::ms_tdStrategy.confirmedCount) ||
            (m_emergStopCount > 0 && m_emergStopCount < KgGlobalData::ms_emgStopStrategy.confirmedCount) ||
            (m_fuseCount > 0 && m_fuseCount < KgGlobalData::ms_fuseStrategy.confirmedCount))
    {
        this->msleep(500);//200
        ret = readDevDIState(KgGlobalData::ms_pStack, KgGlobalData::ms_dryData.failedCount);
    }

    //dealwithConnFailed(runCount); // deleted 2023-11-9

    QString strHint = QString("DIState:%1, DOState:%2, drvFzCnt:%3, drvHzCnt:%4")
            .arg(KgGlobalData::ms_dryData.DIVal).arg(KgGlobalData::ms_dryData.IOCtrl).arg(m_drvFzCount).arg(m_drvHzCount);
    //if (KgGlobalData::ms_hlkgStrategy.diCfg.diIndex < KgGlobalData::ms_devDiCount) // 有采集汇流开关反馈
    if(KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
    {
        strHint += QString(", hlkgState:%1.").arg(getConfSwitchStrState());
    }
    sendLog(0, strHint);

    strHint = QString("***FireAlarm:%1-%2-%3, thunderAlarm:%4-%5-%6, emergStopAlarm:%7-%8-%9.")
            .arg(KgGlobalData::ms_xfStrategy.diList.size()).arg(m_fireAlarmCount).arg(m_fireAlarm)
            .arg(KgGlobalData::ms_tdStrategy.diList.size()).arg(m_thunderCount).arg(m_thunderAlarm)
            .arg(KgGlobalData::ms_emgStopStrategy.diList.size()).arg(m_emergStopCount).arg(m_emergStopAlarm);
    sendLog(0, strHint);

    if(KgGlobalData::ms_dryData.readDiCount > 0)
    {

    }
}


// 获取总交流断路器，直流断路器总合闸个数
int DryCtrlThread::GetCloseDlqCount()
{
    int count = 0;
    CIOModule *pIOModule = ::getIOModule();// KgGlobalData::ms_pRTDB->getIOModule();

    for(int k = 0;  k < KgGlobalData::ms_installBankNum; ++k)
    {
        if(isBankInStack(k))
        {
            if(pIOModule->usDI[3+k] > 0) // 簇直流断路器为合闸状态
            {
                count += 1;
            }
        }
    }

    if(pIOModule->usDI[13] > 0)// 总交流断路器为合闸状态
    {
        count += 1;
    }

    return count;
}

void DryCtrlThread::JudgeXfMotion(int &xfAlarmCount, int &xfMotionCount, int &xfErrorCount, int &xfctrlDlqCount, int runCount)
{
    CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
    CBattStack *pStack = KgGlobalData::ms_pStack;

    int xfAlarm =  pIOModule->usDI[0]; // 消防告警干接点
    int xfMotion = pIOModule->usDI[1]; // 消防动作干接点
    int xfError =  pIOModule->usDI[2]; // 消防故障干接点
    QString strHint;

    /*float fTime = runCount * 50 / 1000; // 运行时间计时，单位：秒
    if(fTime >= 15 && fTime <= 135)
    {
        xfMotion = 1; // 模拟消防动作
    }*/

    if(xfAlarm) // 消防告警
    {
        if(xfAlarmCount < 2000)
            xfAlarmCount += 1;

        if(xfAlarmCount >= 20) // 确认消防告警 1S
        {
            if((runCount % 100) == 0) // 每5秒输出一次
            {
                strHint = QString("===================aFireWarn xfAlarmCount:%1").arg(xfAlarmCount);
                writeKgLogfile(strHint);
            }
            //pStack->aFireWarn = 1;
            if(0 == m_xfAlarmLog)
            {
                saveLogToBaDb(kgConvert("发生消防告警."));
                //saveLogToBaDb(kgConvert(trUtf8("\xE5\x8F\x91\xE7\x94\x9F\xE6\xB6\x88\xE9\x98\xB2\xE5\x91\x8A\xE8\xAD\xA6\x2E")));
                m_xfAlarmLog = 1;
            }
        }
    }
    else
    {
        xfAlarmCount = 0;
        //pStack->aFireWarn = 0;
        if(1 == m_xfAlarmLog)
        {
            saveLogToBaDb(kgConvert("消防告警结束."));
            //saveLogToBaDb(kgConvert(trUtf8("\xE6\xB6\x88\xE9\x98\xB2\xE5\x91\x8A\xE8\xAD\xA6\xE7\xBB\x93\xE6\x9D\x9F\x2E")));
            m_xfAlarmLog = 0;
        }
    }

    if(xfMotion > 0)// 消防动作
    {
        if(xfMotionCount < 2000)
            xfMotionCount += 1;

        if(xfMotionCount >= 4) // 确认消防动作 0.2S
        {
            if((xfMotionCount % 100) == 4)
            {
                strHint = QString("===================aFireAction!!! xfMotionCount:%1, xfctrlDlqCount:%2").arg(xfMotionCount).arg(xfctrlDlqCount);
                writeKgLogfile(strHint);
            }

            pStack->aFireAction = 1;

            //writeKgLogfile("step600");

            // (1) 先通知PCS
            if(0 == xfctrlDlqCount)
            {
                TellPcsError(xfMotionCount, runCount, 0);
            }
            if(0 == m_xfXfMotionLog)
            {
                saveLogToBaDb(kgConvert("发生消防动作."));
                //saveLogToBaDb(kgConvert(trUtf8("\xE5\x8F\x91\xE7\x94\x9F\xE6\xB6\x88\xE9\x98\xB2\xE5\x8A\xA8\xE4\xBD\x9C\x2E")));
                m_xfXfMotionLog = 1;
            }
            //writeKgLogfile("step601");

            // (2) 控制总断路器断开
            int closeDqlCount = 0;
            if(xfctrlDlqCount > 0 && xfctrlDlqCount < 3) // 已经有操作控制断开, 延时一下再看操作结果
            {
                closeDqlCount = GetCloseDlqCount();
                //writeKgLogfile(QString("step601-1  closeDqlCount:%1").arg(closeDqlCount));
                if(closeDqlCount > 0) // 还有断路路没断开
                {
                    this->msleep(1000);
                    closeDqlCount = GetCloseDlqCount();
                    //writeKgLogfile("step601-2");
                }

                if(0 == closeDqlCount) // 已全部断开，操作结束
                {
                    xfctrlDlqCount = 3;
                }
            }

            //writeKgLogfile("step602");

            if(0 == xfctrlDlqCount || (xfctrlDlqCount < 3 && closeDqlCount > 0))// 为第一次操作 或为[第2，3次操作且仍有未断开]
            {
                xfctrlDlqCount += 1;
                if(xfctrlDlqCount > 1) // 第2，3次尝试分闸时才输出
                {
                    writeKgLogfile(QString("************************%1th control FZ when recevie XF motion, closeDqlCount:%2.")
                                   .arg(xfctrlDlqCount).arg(closeDqlCount));
                }

                // 消防动作被触发后，常开变常闭（维持2S），让监控配电一体柜1~10#直流断路器及总交流断路器断开
                pIOModule->usDOCtrl[0] = 1;

                for(int k = 0; k < 20; ++k)
                {
                    this->msleep(100);
                    if(5 == k || 10 == k || 15 == k)
                    {
                        printDiDoState();
                    }
                }

                pIOModule->usDOCtrl[0] = 0;
            }
            //writeKgLogfile("step603");
        }
    }
    else
    {
        xfMotionCount = 0;
        xfctrlDlqCount = 0;
        pStack->aFireAction = 0;

        if(1 == m_xfXfMotionLog)
        {
            saveLogToBaDb(kgConvert("消防动作结束."));
            //saveLogToBaDb(kgConvert(trUtf8("\xE6\xB6\x88\xE9\x98\xB2\xE5\x8A\xA8\xE4\xBD\x9C\xE7\xBB\x93\xE6\x9D\x9F\x2E")));
            m_xfXfMotionLog = 0;
        }
    }

    if(xfError)// 消防故障
    {
        if(xfErrorCount < 2000)
            xfErrorCount += 1;

        if(xfErrorCount >= 20) // 确认消防故障 1S
        {
            if((runCount % 100) == 0) // 每5秒输出一次
            {
                strHint = QString("===================aFireFault xfErrorCount:%1").arg(xfErrorCount);
                writeKgLogfile(strHint);
            }
            //pStack->aFireFault = 1;

            if(0 == m_xfXfErrorLog)
            {
                saveLogToBaDb(kgConvert("发生消防故障."));
                //saveLogToBaDb(kgConvert(trUtf8("\xE5\x8F\x91\xE7\x94\x9F\xE6\xB6\x88\xE9\x98\xB2\xE6\x95\x85\xE9\x9A\x9C\x2E")));
                m_xfXfErrorLog = 1;
            }
        }
    }
    else
    {
        xfErrorCount = 0;
        //pStack->aFireFault = 0;
        if(1 == m_xfXfErrorLog)
        {
            saveLogToBaDb(kgConvert("消防故障结束."));
            //saveLogToBaDb(kgConvert(trUtf8("\xE6\xB6\x88\xE9\x98\xB2\xE6\x95\x85\xE9\x9A\x9C\xE7\xBB\x93\xE6\x9D\x9F\x2E")));
            m_xfXfErrorLog = 0;
        }
    }
}

// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 1#系统故障 !!!    aEnvTemp[0] 
// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 2#系统故障 !!!    aEnvTemp[4] 
// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 系统缺水告警 !!!  aEnvTemp[10] 
// pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 电源故障告警 !!!  aEnvTemp[13] 
QString getYljErrorName(CBattStack *pStack)
{

    QString strError;
    if(pStack->aEnvTemp[0] > 0 && pStack->aEnvTemp[4] > 0)
    {
        strError = QString("1#,2#系统故障");
    }
    else if(pStack->aEnvTemp[0] > 0)
    {
        strError = QString("1#系统故障");
    }
    else if(pStack->aEnvTemp[4] > 0)
    {
        strError = QString("2#系统故障");
    }
    else
        ;

    if(pStack->aEnvTemp[10] > 0)// 系统缺水告警
    {
        if(strError.length() > 2)
        {
            strError += ",";
        }
        strError += QString("系统缺水告警");
    }

    if(pStack->aEnvTemp[13] > 0)// 电源故障告警
    {
        if(strError.length() > 2)
        {
            strError += ",";
        }
        strError += QString("电源故障");
    }

    return strError;
}

void DryCtrlThread::JudgeYljError(int &yljProtCount, int &xfctrlDlqCount, int runCount)// added 2023-10-25
{
    CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
    CBattStack *pStack = KgGlobalData::ms_pStack;
    QString strHint;
    int yljProtSum = pStack->aEnvTemp[0] + pStack->aEnvTemp[4] + pStack->aEnvTemp[10] + pStack->aEnvTemp[13];
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 1#系统故障 !!!    aEnvTemp[0]
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 2#系统故障 !!!    aEnvTemp[4]
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 系统缺水告警 !!!  aEnvTemp[10]
    // pStack->aEnvTemp[pos++] = retList[k++].toInt();// 水冷机 电源故障告警 !!!  aEnvTemp[13]
    
    if(yljProtSum > 0)// 消防动作
    {
        if(yljProtCount < 2000)
            yljProtCount += 1;

        if(yljProtCount >= 4) // 确认保护动作 0.2S
        {
            if((yljProtCount % 100) == 4)
            {
                strHint = QString("===================aYljError!!! yljProtCount:%1, xfctrlDlqCount:%2").arg(yljProtCount).arg(xfctrlDlqCount);
                writeKgLogfile(strHint);
            }

            //pStack->aFireAction = 1;

            //writeKgLogfile("step600");

            // (1) 先通知PCS
            if(0 == xfctrlDlqCount)
            {
                TellPcsError(yljProtCount, runCount, 0);
            }
            if(0 == m_yljErrorLog)
            {
                saveLogToBaDb(kgConvert("水冷机发生:%1.").arg(getYljErrorName(pStack)));
                //saveLogToBaDb(kgConvert(trUtf8("\xE5\x8F\x91\xE7\x94\x9F\xE6\xB6\x88\xE9\x98\xB2\xE5\x8A\xA8\xE4\xBD\x9C\x2E")));
                m_yljErrorLog = 1;
            }
            //writeKgLogfile("step601");

            // (2) 控制总断路器断开
            int closeDqlCount = 0;
            if(xfctrlDlqCount > 0 && xfctrlDlqCount < 3) // 已经有操作控制断开, 延时一下再看操作结果
            {
                closeDqlCount = GetCloseDlqCount();
                //writeKgLogfile(QString("step601-1  closeDqlCount:%1").arg(closeDqlCount));
                if(closeDqlCount > 0) // 还有断路器没断开
                {
                    this->msleep(1000);
                    closeDqlCount = GetCloseDlqCount();
                    //writeKgLogfile("step601-2");
                }

                if(0 == closeDqlCount) // 已全部断开，操作结束
                {
                    xfctrlDlqCount = 3;
                }
            }

            //writeKgLogfile("step602");

            if(0 == xfctrlDlqCount || (xfctrlDlqCount < 3 && closeDqlCount > 0))// 为第一次操作 或为[第2，3次操作且仍有未断开]
            {
                xfctrlDlqCount += 1;
                if(xfctrlDlqCount > 1) // 第2，3次尝试分闸时才输出
                {
                    writeKgLogfile(QString("************************%1th control FZ when recevie XF motion, closeDqlCount:%2.")
                                   .arg(xfctrlDlqCount).arg(closeDqlCount));
                }

                // 消防动作被触发后，常开变常闭（维持2S），让监控配电一体柜1~10#直流断路器及总交流断路器断开
                pIOModule->usDOCtrl[0] = 1;

                for(int k = 0; k < 20; ++k)
                {
                    this->msleep(100);
                    if(5 == k || 10 == k || 15 == k)
                    {
                        printDiDoState();
                    }
                }

                pIOModule->usDOCtrl[0] = 0;
            }
            //writeKgLogfile("step603");
        }
    }
    else
    {
        yljProtCount = 0;
        xfctrlDlqCount = 0;
        //pStack->aFireAction = 0;

        if(1 == m_yljErrorLog)
        {
            saveLogToBaDb(kgConvert("水冷机故障结束."));
            //saveLogToBaDb(kgConvert(trUtf8("\xE6\xB6\x88\xE9\x98\xB2\xE5\x8A\xA8\xE4\xBD\x9C\xE7\xBB\x93\xE6\x9D\x9F\x2E")));
            m_yljErrorLog = 0;
        }
    }
}

//int g_ctrlCount[10] = {0,0,0,0,0,0,0,0,0,0};
void DryCtrlThread::TellPcsError(int xfMotionCount, int runCount, int needTkQlq)
{
    CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
    CBattStack *pStack = KgGlobalData::ms_pStack;
    QString strHint;

    // 各簇的PCS故障干节点处理
    int hasSysError = 0;
    for(int k = 0;  k < KgGlobalData::ms_installBankNum; ++k)
    {
        //if(k > 1)
        //	break;
        //if(isBankInStack(k))
        {
            CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);
            if((runCount % 100) == 0) // 每5秒输出一次
            {
                if(needTkQlq)
                {
                    QChar fillChar = '0';
                    QString strState = QString("0X%1").arg(pBank->usBankState,4,16,fillChar).toUpper();
                    strHint = QString("=====Bank%1 runStateDO3:%2, errStateDO4:%3,DO5State:%4, usDI1to3:%5-%6-%7,bankState:%8")
                            .arg(k+1).arg(pBank->usDry3State).arg(pBank->usDry4State).arg(pBank->usDry5State)
                            .arg(pBank->usDI1).arg(pBank->usDI2).arg(pBank->usDI3).arg(strState);
                    strHint += QString(",BankVol:%1V,BankCur:%2A").arg(pBank->fBankVol).arg(pBank->fBankCur);
                    if(0xAAAA == pBank->usBankState || xfMotionCount >= 4)
                    {
                        strHint += "(Tell PCS error).";
                    }
                    writeKgLogfile(strHint);
                }
            }

            // added 2023-6-30
            if(0xAAAA == pBank->usBankState)
            {
                int almLevel3 = 0;

                if(1)
                {
                    if(m_bankFaultTimeCount[k] < 10000)
                    {
                        m_bankFaultTimeCount[k] += 1;
                    }
                }
                else
                {
                    m_bankFaultTimeCount[k] = 0;
                }
            }
            else
            {
                m_bankFaultTimeCount[k] = 0;
            }

            // 发生故障， 或有消防启动信号，
            if((0xAAAA == pBank->usBankState && 0 == pBank->usNeedCloseJCQ) || (xfMotionCount >= 4))
            {
                hasSysError = 1;
                pIOModule->usDOCtrl[1+k] = 1; // PCS故障干节点

                if(needTkQlq)
                {

                    if(xfMotionCount >= 4 || 0xBBBB == m_oldBankState[k])
                    {
                        if(1 == KgGlobalData::ms_isGaoTeVer) // modified 2023-8-9
                        {
                            if(1 == pBank->usDI3)
                                //if(0 == pBank->usDry3State)
                            {
                                saveLogToBaDb(QString("发生故障，控制#%1簇脱扣.").arg(k+1));
                                pBank->usBankTemp[28] = 0;
                                pBank->usDry3Ctrl = 1;    // 干接点3控制  分励驱动断路器 DO3 // GaoTe
                                pBank->iDry3CtrlNum = 3;  // 干接点3控制次数
                            }
                        }
                        else
                        {
                            if(1 == pBank->usDI3)
                                //if(0 == pBank->usDry5State)
                            {
                                saveLogToBaDb(QString("发生故障，控制#%1簇脱扣.").arg(k+1));
                                pBank->usBankTemp[28] = 0;
                                pBank->usDry5Ctrl = 1;    // 干接点5控制  分励驱动断路器 DO5
                                pBank->iDry5CtrlNum = 3;  // 干接点5控制次数
                            }
                        }
                        m_oldBankState[k] = 0xAAAA;
                    }
                    else
                    {
                        //printf("1===pBank->usBankTemp[28]===============%d\n", pBank->usBankTemp[28]);
                        if(pBank->usBankTemp[28] < 100)// 400
                        {
                            pBank->usBankTemp[28] += 1;
                        }
                        else if(pBank->usBankTemp[28] < 200)
                        {
                            pBank->usBankTemp[28] += 1;
                            if(1 == KgGlobalData::ms_isGaoTeVer)
                            {
                                //if(1 == pBank->usDry3State)
                                //{
                                pBank->usDry3Ctrl = 0;       // 干接点3控制
                                pBank->iDry3CtrlNum = 3;     // 干接点3控制次数
                                //}
                            }
                            else
                            {
                                //if(1 == pBank->usDry5State)
                                //{
                                pBank->usDry5Ctrl = 0;       // 干接点5控制
                                pBank->iDry5CtrlNum = 3;     // 干接点5控制次数
                                //}
                            }
                        }
                        else
                        {
                            ;
                        }
                    }
                }
            }
            else
            {
                //printf("2====pBank->usBankTemp[28]===============%d\n", pBank->usBankTemp[28]);
                if(0xBBBB == pBank->usBankState || 0x1111== pBank->usBankState || 0x2222 == pBank->usBankState ||
                        0xCCCC == pBank->usBankState || 0x5555 == pBank->usBankState)
                {
                    m_oldBankState[k] = 0xBBBB;
                }

                pIOModule->usDOCtrl[1+k] = 0;// PCS故障干节点

                if(pBank->usBankTemp[28] < 100)// 400
                {
                    pBank->usBankTemp[28] += 1;
                }
                else if(pBank->usBankTemp[28] < 200)
                {
                    pBank->usBankTemp[28] += 1;
                    if(1 == KgGlobalData::ms_isGaoTeVer)
                    {
                        //if(1 == pBank->usDry3State)
                        //{
                        pBank->usDry3Ctrl = 0;       // 干接点3控制
                        pBank->iDry3CtrlNum = 3;     // 干接点3控制次数
                        //}
                    }
                    else
                    {
                        //if(1 == pBank->usDry5State)
                        //{
                        pBank->usDry5Ctrl = 0;       // 干接点5控制
                        pBank->iDry5CtrlNum = 3;     // 干接点5控制次数
                        //}
                    }
                }
                else
                {
                    ;
                }
            }
        }
    }

    if(hasSysError)
    {
        pIOModule->usDOCtrl[11] = 1;       // 故障指示灯硬接点 DO12
    }
    else
    {
        pIOModule->usDOCtrl[11] = 0;
    }
}

// 判断各簇QF1开关状态 
void DryCtrlThread::JudgeDIState()
{
    CIOModule *pIOModule = ::getIOModule();// KgGlobalData::ms_pRTDB->getIOModule();
    if(0 == m_hasReadIoState) // 还没有读取DI
    {
        m_hasReadIoState = 1;
        for(int i = 0; i < 10; ++i)
        {
            m_usOldDI[3+i] = pIOModule->usDI[3+i];
        }
    }
    else
    {
        for(int i = 0; i < 10; ++i)
        {
            quint16 newDI = pIOModule->usDI[3+i];
            if(m_usOldDI[3+i] != newDI)// 簇QF1开关状态发生变化
            {
                m_usOldDI[3+i] = newDI;
                QString strLog;
                if(newDI)
                    strLog = QString("#%1簇QF1开关闭合.").arg(i+1);
                else
                    strLog = QString("#%1簇QF1开关断开.").arg(i+1);
                //writeKgLogfile(strLog);
                saveLogToBaDb(strLog);
            }
        }
    }
}

void DryCtrlThread::SaveEmsFltkLog()
{
    /*
    for(int k = 0;  k < KgGlobalData::ms_installBankNum; ++k)
    {
        //if(isBankInStack(k))
        {
            CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);
            if(1000 == pBank->usBankTemp[28])// 有EMS分励驱动断路器，xnextio收到后进行日志记录
            {
                 pBank->usBankTemp[28] = 0;
                 QString strLog = QString("EMS控制%1#簇高压箱分励脱扣.").arg(k+1);
                 saveLogToBaDb(strLog);
            }
        }
    }
    */
}

// 高特运行灯，故障处理 added 2023-7-28
// DO3-断路器 DO6-故障指示灯 DO7-运行指示灯
void DryCtrlThread::ctrlErrorLamp(CBattStack *pStack)
{
    for(int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
        if(pBank)
        {
            if(0xAAAA == pBank->usBankState) // 故障
            {
                if(0 == pBank->usDry5State) // 点亮 DO6故障灯
                {
                    pBank->usDry5Ctrl = 1;
                    pBank->iDry5CtrlNum = 3;
                }
                if(1 == pBank->usDry6State)
                {
                    pBank->usDry6Ctrl = 0;
                    pBank->iDry6CtrlNum = 3;
                }
            }
            else  // 正常
            {
                if(1 == pBank->usDry5State)
                {
                    pBank->usDry5Ctrl = 0;
                    pBank->iDry5CtrlNum = 3;
                }
                if(0 == pBank->usDry6State)// 点亮 DO7运行灯
                {
                    pBank->usDry6Ctrl = 1;
                    pBank->iDry6CtrlNum = 3;
                }
            }
        }
    }
}

int printConfSwitchCount = 0;
void DryCtrlThread::dealWithConfSwitchStrategy(CBattStack *pStack)
{
    if(printConfSwitchCount < 50)
    {
        printConfSwitchCount += 1;
        QString strLog = QString("****************usConfSwitchStrategy:%1, diSize:%2 ")
                .arg(pStack->usConfSwitchStrategy).arg(KgGlobalData::ms_hlkgStrategy.diCfgList.size());
        writeKgLogfile(strLog);
    }

    if(0 == KgGlobalData::ms_confSwitchEnabled)
    {
        if(3 == pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 0;
            updateConfSwitchStrategy(0);
            QString strLog = kgConvert("取消汇流开关策略, 重启生效.");
            saveLogToBaDb(strLog);
        }
        return;
    }

    if(2 == KgGlobalData::ms_confSwitchEnabled)// 强制显示 // added 2024-10-15
    {
        if(3 != pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 3; // 汇流开关策略    1 - BC 2- BA 3 - ExtIO
            updateConfSwitchStrategy(3);
            QString strLog = kgConvert("配置汇流开关策略, 重启生效.");
            saveLogToBaDb(strLog);
        }
        return;
    }

    if(KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
    {
        if(3 != pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 3; // 汇流开关策略    1 - BC 2- BA 3 - ExtIO
            updateConfSwitchStrategy(3);
            QString strLog = kgConvert("配置汇流开关策略, 重启生效.");
            saveLogToBaDb(strLog);
        }
    }
    else
    {
        if(3 == pStack->usConfSwitchStrategy)
        {
            pStack->usConfSwitchStrategy = 0;
            updateConfSwitchStrategy(0);
            QString strLog = kgConvert("取消汇流开关策略, 重启生效.");
            saveLogToBaDb(strLog);
        }
    }

    this->msleep(500);

    if(printConfSwitchCount < 50)
    {
        printConfSwitchCount += 1;
        QString strLog = QString("****************usConfSwitchStrategy:%1, diSize:%2 ")
                .arg(pStack->usConfSwitchStrategy).arg(KgGlobalData::ms_hlkgStrategy.diCfgList.size());
        writeKgLogfile(strLog);
    }
}


// 2022-3-30测试 616ms循环一次 DryCtrl/XfConfirmedCount配置为6时，从检测到消防信号，到报消防告警大约需3秒
// 2023-6-16
void DryCtrlThread::run()
{
    int ret = 0;
    quint16 runCount = 0;
    QString strHint;
    DryData &m_Para = KgGlobalData::ms_dryData;

    sleep(1);//程序刚启动时，本程序晚一点运行
    //m_pRtuClient = new CXnSerial;// Client
    m_pRTDB = KgGlobalData::ms_pRTDB;
    m_pStack = KgGlobalData::ms_pRTDB->getStack(0);
    CBattStack *pStack = m_pStack;

    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(0);

    if(KgGlobalData::ms_pStack != 0)
    {
        dealWithConfSwitchStrategy(KgGlobalData::ms_pStack);
    }


    
    // 其他初始化代码继续执行
    writeKgLogfile(QString("step500 usStackCfgInfo:%1").arg(pStack->usStackCfgInfo));
    //saveLogToBaDb(kgConvert("IO程序开始运行."));
    int tickCount = 0;
    int judgeDiCount = 0;
    int softRunTime = 0;
    CIOModule *pIOModule = ::getIOModule();// KgGlobalData::ms_pRTDB->getIOModule();
    int xfAlarmCount = 0;
    int xfMotionCount = 0;
    int xfErrorCount = 0;
    int xfctrlDlqCount = 0; // 消防时控制总交流断路器断开次数

    int yljProtCount = 0;
    QChar c = '0';
    QString strState;

    writeKgLogfile(QString("======usRunLampCtrlDONo:%1, usFaultLampCtrlDONo:%2").arg(pStack->usRunLampCtrlDONo).arg(pStack->usFaultLampCtrlDONo));
    printf("usPackPowerLineStrategy:%d, usBankPowerLineStrategy:%d\n",
           pStack->usPackPowerLineStrategy,pStack->usBankPowerLineStrategy);

    for(int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
    {
        CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
        if(pBank)
        {
            int pos = 0;
            QString strTemp = QString("Bank%1 temp1--10:%2,%3,%4,%5,%6,  %7,%8,%9,%10,%11").arg(i+1)
                    .arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++])
                    .arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]).arg(pBank->fSglTemp[pos++]);
            writeKgLogfile(strTemp);

            printf("****Bank%d DO1-DO8 state:%d(Wet)-%d-%d-%d(DO4)-%d(DO5)-%d(DO6)-%d(DO7)-%d(DO8)\n",
                   i+1, pBank->usWetState, pBank->usDry1State, pBank->usDry2State, pBank->usDry3State,
                   pBank->usDry4State,pBank->usDry5State,pBank->usDry6State,pBank->usDry7State);
            continue;

            writeKgLogfile(QString("=====Bank%1 BankVol:%2, BankCur:%3.").arg(i+1).arg(pBank->fBankVol).arg(pBank->fBankCur));
            QChar fillChar = '0';
            QString strState = QString("0X%1").arg(pBank->usBankState,4,16,fillChar).toUpper();
            strHint = QString("=====Bank%1 runStateDO3:%2, errStateDO4:%3,DO5State:%4, usDI1to3:%5-%6-%7,bankState:%8")
                    .arg(i+1).arg(pBank->usDry3State).arg(pBank->usDry4State).arg(pBank->usDry5State)
                    .arg(pBank->usDI1).arg(pBank->usDI2).arg(pBank->usDI3).arg(strState);

        }
    }

    // added 2023-7-28
    if(1 == KgGlobalData::ms_isGaoTeVer)
    {
        pStack->usFaultLampCtrlDONo = 0; // 故障灯控制  1 ~ 5, DO1 ~ DO5
        pStack->usRunLampCtrlDONo = 0;   // 运行灯控制  1 ~ 5, DO1 ~ DO5
    }

    printf("1=====aEnvTemp[0]to[5]:%d-%d-%d-%d-%d-%d\n", pStack->aEnvTemp[0],pStack->aEnvTemp[1],
           pStack->aEnvTemp[2],pStack->aEnvTemp[3],pStack->aEnvTemp[4],pStack->aEnvTemp[5]);


    printf("1=====aWaterAlarm:%d, aEnvWaterAlarm[0]:%d,bank aWaterAlarm:%d\n",
           pStack->aWaterAlarm,pStack->aEnvWaterAlarm[0],0);// pBank->aWaterAlarm

    sleep(2);

    if(KgGlobalData::ms_emgStopStrategy.diList.size() > 0)
        pStack->usEmerStopStrategy    = 3;// 紧急停机策略     1 - BC 2- BA 3 - ExtIO
    if(KgGlobalData::ms_xfStrategy.diList.size() > 0)
        pStack->usFireWarnStrategy   = 3; // 消防预警策略     1 - BC 2- BA 3 - ExtIO
    if(KgGlobalData::ms_xfSprayStrategy.diList.size() > 0)
        pStack->usFireActionStrategy = 3; // 消防启动策略     1 - BC 2- BA 3 - ExtIO
    if(KgGlobalData::ms_xfFaultStrategy.diList.size() > 0)
        pStack->usFireFaultStrategy = 3; // 消防故障策略     1 - BC 2- BA 3 - ExtIO
    if(KgGlobalData::ms_waterStrategy.diList.size() > 0)
        pStack->usWaterStrategy = 3;     // 水浸告警策略     1 - BC 2- BA 3 - ExtIO
    if(KgGlobalData::ms_combusGasStrategy.diList.size() > 0)
        pStack->usGasStrategy = 3;// 可燃气体策略     1 - BC 2- BA 3 - ExtIO
    if(KgGlobalData::ms_doorAlmStrategy.diList.size() > 0)
        pStack->usAcceCtrlStrategy = 3;// 门禁状态策略     1 - BC 2- BA 3 - ExtIO

    while(1)
    {
        msleep(100);

        netDebug->kgWrite(QString("在线程的循环当中"));
        dealwithBcmuAddressAllocation();
        if (runCount < 5)
        {
            CIOModule *m_pIOModule = KgGlobalData::ms_pIOModule;
            printf("DryCtrlThread read usDOCtrl1-12:%d-%d-%d-%d-%d-%d, %d-%d-%d-%d-%d-%d\n",
                   m_pIOModule->usDOCtrl[0],m_pIOModule->usDOCtrl[1],m_pIOModule->usDOCtrl[2],m_pIOModule->usDOCtrl[3],
                   m_pIOModule->usDOCtrl[4],m_pIOModule->usDOCtrl[5],m_pIOModule->usDOCtrl[6],m_pIOModule->usDOCtrl[7],
                   m_pIOModule->usDOCtrl[8],m_pIOModule->usDOCtrl[9],m_pIOModule->usDOCtrl[10],m_pIOModule->usDOCtrl[11]);
        }

        if(softRunTime < 30000)
        {
            softRunTime += 1;
        }

        //if(++tickCount >= 60) // 每3秒输出一次
        {
            tickCount = 0;
            printDiDoState();
            int closeDqlCount = GetCloseDlqCount();
            writeKgLogfile(QString("closeDqlCount:%1").arg(closeDqlCount));
        }

#ifdef VER20_EMS
        CXfData *pXfData = KgGlobalData::ms_pRTDB->getXfDev(0);
#endif		
        if (runCount < 100)
        {
            runCount += 1;

            writeKgLogfile(QString("step101 aEmerStop:%1,aFireWarn:%2,aFireAction:%3,aFireFault:%4.")
                           .arg((int)pStack->aEmerStop).arg((int)pStack->aFireWarn).arg((int)pStack->aFireAction)
                           .arg((int)pStack->aFireFault));

#ifdef VER20_EMS
            writeKgLogfile(QString("aEnvWaterAlarm:%1, xfData connError:%2, usDevTemp[0]:%3(state), usDevTemp[1]:%4(level), usDevTemp[2]:%5.")
                           .arg((int)pStack->aEnvWaterAlarm[0]).arg((int)pXfData->connError).arg((int)pXfData->usDevTemp[0]).arg((int)pXfData->usDevTemp[1]).arg((int)pXfData->usDevTemp[2]));
#endif		
            strState = QString("%1").arg(pBank->usBankState,4,16,c).toUpper();
            writeKgLogfile(QString("BankState:0X%1,usChgState:%2,DIState:%3-%4-%5-%6-%7-%8.")
                           .arg(strState).arg((int)pBank->usBankChgDchgState).arg(pBank->usDI1)
                           .arg(pBank->usDI2).arg(pBank->usDI3).arg(pBank->usDI4).arg(pBank->usDI5).arg(pBank->usDI6));

            writeKgLogfile(QString("aAcceCtrlState:%1-%2,aWaterAlarm:%3,aEnvWaterAlarm[0][1]:%4,%5.")
                           .arg((int)pStack->aAcceCtrlState).arg((int)pStack->aEnvTemp[10])
                           .arg((int)pStack->aWaterAlarm).arg((int)pStack->aEnvWaterAlarm[0]).arg((int)pStack->aEnvWaterAlarm[1]));

            writeKgLogfile(QString("485Water:%1-%2(aEnvTemp[30]-[31]), 485xfAlarm:%3-%4(aEnvTemp[32]-[33]), xfMotion:%5,%6(aEnvTemp[34]-[35]), xfFault:%7-%8(aEnvTemp[36]-[37]) runCount:%9.")
                           .arg((int)pStack->aEnvTemp[30]).arg((int)pStack->aEnvTemp[31])
                           .arg((int)pStack->aEnvTemp[32]).arg((int)pStack->aEnvTemp[33])
                           .arg((int)pStack->aEnvTemp[34]).arg((int)pStack->aEnvTemp[35])
                           .arg((int)pStack->aEnvTemp[36]).arg((int)pStack->aEnvTemp[37])
                           .arg(runCount));

            writeKgLogfile(QString("m_bmsLocalState:%1, m_bmsRemoteState:%2.")
                           .arg((int)m_bmsLocalState).arg((int)m_bmsRemoteState));
        }
        else if (runCount < 30000)
        {
            runCount += 1;
            writeKgLogfile(QString("step101 aEmerStop:%1,aFireWarn:%2,aFireAction:%3,aFireFault:%4, aEnvTemp[49]:%5.")
                           .arg((int)pStack->aEmerStop).arg((int)pStack->aFireWarn).arg((int)pStack->aFireAction)
                           .arg((int)pStack->aFireFault).arg((int)pStack->aEnvTemp[49]));
#ifdef VER20_EMS
            writeKgLogfile(QString("aEnvWaterAlarm:%1, xfData connError:%2, usDevTemp[0]:%3(state), usDevTemp[1]:%4(level), usDevTemp[2]:%5.")
                           .arg((int)pStack->aEnvWaterAlarm[0]).arg((int)pXfData->connError).arg((int)pXfData->usDevTemp[0]).arg((int)pXfData->usDevTemp[1]).arg((int)pXfData->usDevTemp[2]));
#endif			
            writeKgLogfile(QString("485Water:%1-%2(aEnvTemp[30]-[31]), 485xfAlarm:%3-%4(aEnvTemp[32]-[33]), xfMotion:%5,%6(aEnvTemp[34]-[35]), xfFault:%7-%8(aEnvTemp[36]-[37]) runCount:%9.")
                           .arg((int)pStack->aEnvTemp[30]).arg((int)pStack->aEnvTemp[31])
                           .arg((int)pStack->aEnvTemp[32]).arg((int)pStack->aEnvTemp[33])
                           .arg((int)pStack->aEnvTemp[34]).arg((int)pStack->aEnvTemp[35])
                           .arg((int)pStack->aEnvTemp[36]).arg((int)pStack->aEnvTemp[37])
                           .arg(runCount));
        }
        else
            ;

        getInstallInfo();

        CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
        if (pStack)
        {

        }



        if(0 == KgGlobalData::ms_pStack)
        {
            printf("pStack is null.\n");
            this->msleep(2000);
            continue;
        }

        if(999 == KgGlobalData::ms_zz404D_addr)
        {
            KgGlobalData::ms_pStack->aExIOModuConnFault = 0;
            if(KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
            {
                KgGlobalData::ms_pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
                KgGlobalData::ms_pStack->aConfSwitchState = 0;
            }
            //writeKgLogfile(QString("Do not have IO module"));
            msleep(200);
            continue;
        }
        else if(1000 == KgGlobalData::ms_zz404D_addr)
        {
            KgGlobalData::ms_pStack->aExIOModuConnFault = 1;
            if(KgGlobalData::ms_hlkgStrategy.diCfgList.size() > 0)
            {
                KgGlobalData::ms_pStack->usConfSwitchState = 2;//通知BA 汇流开关已经断开
                KgGlobalData::ms_pStack->aConfSwitchState = 0;
            }
            msleep(200);
            continue;
        }
        else
            ;


        m_pIOReader->readDevDOState(0, KgGlobalData::ms_dryData);
        // writeKgLogfile(QString("step502"));

        // 第2帧：根据工况设置DO (如果状态没有改变，则不下发)========================2 Set DO
        setSomeDOState();

        if(runCount >= 5) // 3 // modifed 2023-12-14
        {
            if(KgGlobalData::ms_execFltkFirst)
            {
                controlOtherFz();// 控制其他脱扣

                if(KgGlobalData::ms_hlkgStrategy.xfTkDoList.size() > 0 && m_xfTkMotionCount > 0 &&  m_xfTkMotionCount < KgGlobalData::ms_ctrlConfSwitchCount)
                {
                    // Doing TuoKou1 3 times first
                }
                else if(KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.size() > 0 && m_xfSprayTkMotionCount > 0 &&  m_xfSprayTkMotionCount < KgGlobalData::ms_ctrlConfSwitchCount)
                {
                    // Doing TuoKou2 3 times first
                }
                else if(KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.size() > 0 && m_volDownProtTkCount > 0 &&  m_volDownProtTkCount < KgGlobalData::ms_ctrlConfSwitchCount)
                {
                    // Doing TuoKou2 3 times first
                }
                else
                {
                    controlHzFz();   // 控制汇流开关，此处有延时，所以要单独分开执行
                }
            }
            else
            {
                controlHzFz();   // 控制汇流开关，此处有延时，所以要单独分开执行
                controlOtherFz();// 控制其他脱扣
            }
        }


        msleep(50);
        readDIValue(runCount);
        
        // 检查DI状态变化并更新到ini文件
       // updateDIStateToIniFile();

#ifdef HAS_SECOND_IO_DEV
        // 读取第二个IO模块的DI数据 // added 2022-8-2
        int oldDIVal = KgGlobalData::ms_drySecData.DIVal;
        m_pIOReader->readDevDIState(1, KgGlobalData::ms_drySecData);//查询成功
        if(oldDIVal != KgGlobalData::ms_drySecData.DIVal)
        {
            this->msleep(500);
            m_pIOReader->readDevDIState(1, KgGlobalData::ms_drySecData);//查询成功
        }
#endif	
        if (runCount >= 1)
        {
            // deleted 2023-11-9
            updateDryDataToRtdb(this);    //更新DI1-4数据到BA的通用保持寄存器50-53中 2020-1-15
        }
    }
}
